xref: /openbsd/sbin/disklabel/editor.c (revision a49bdda8)
1*a49bdda8Skrw /*	$OpenBSD: editor.c,v 1.241 2010/07/27 00:49:42 krw Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
42d8451b0Smillert  * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert  */
186fe57b42Smillert 
196fe57b42Smillert #include <sys/types.h>
206fe57b42Smillert #include <sys/param.h>
21c33fcabaSmillert #include <sys/stat.h>
22c33fcabaSmillert #include <sys/ioctl.h>
2391f4f7d8Sdlg #include <sys/dkio.h>
248dde8bb6Sotto #include <sys/sysctl.h>
256fe57b42Smillert #define	DKTYPENAMES
266fe57b42Smillert #include <sys/disklabel.h>
276fe57b42Smillert 
286fe57b42Smillert #include <ufs/ffs/fs.h>
296fe57b42Smillert 
306fe57b42Smillert #include <ctype.h>
316fe57b42Smillert #include <err.h>
326fe57b42Smillert #include <errno.h>
336fe57b42Smillert #include <string.h>
34803ff7d5Smillert #include <libgen.h>
356fe57b42Smillert #include <stdio.h>
366fe57b42Smillert #include <stdlib.h>
376fe57b42Smillert #include <unistd.h>
386fe57b42Smillert 
39f21a098bSotto #include "extern.h"
404793b14cSmillert #include "pathnames.h"
414793b14cSmillert 
426fe57b42Smillert /* flags for getuint() */
436fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
446fe57b42Smillert #define	DO_ROUNDING	0x00000002
456fe57b42Smillert 
46f98aebd4Smillert #ifndef NUMBOOT
47f98aebd4Smillert #define NUMBOOT 0
48f98aebd4Smillert #endif
49f98aebd4Smillert 
5096a888c6Smillert /* structure to describe a portion of a disk */
5196a888c6Smillert struct diskchunk {
521e0ad43cSotto 	u_int64_t start;
531e0ad43cSotto 	u_int64_t stop;
5496a888c6Smillert };
5596a888c6Smillert 
563f843443Smillert /* used when sorting mountpoints in mpsave() */
573f843443Smillert struct mountinfo {
583f843443Smillert 	char *mountpoint;
593f843443Smillert 	int partno;
603f843443Smillert };
613f843443Smillert 
62557f712bSkrw /* used when allocating all space according to recommendations */
63557f712bSkrw 
64557f712bSkrw struct space_allocation {
655f3e1104Skrw 	daddr64_t	minsz;	/* starts as blocks, xlated to sectors. */
665f3e1104Skrw 	daddr64_t	maxsz;	/* starts as blocks, xlated to sectors. */
67557f712bSkrw 	int		rate;	/* % of extra space to use */
68557f712bSkrw 	char 	       *mp;
69557f712bSkrw };
70557f712bSkrw 
718dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
728dde8bb6Sotto const struct space_allocation alloc_big[] = {
7392adb55fSderaadt 	{   MEG(80),         GIG(1),   5, "/"		},
748dde8bb6Sotto 	{   MEG(80),       MEG(256),   5, "swap"	},
754ab111d2Sderaadt 	{  MEG(120),         GIG(4),   8, "/tmp"	},
7692adb55fSderaadt 	{   MEG(80),         GIG(4),  13, "/var"	},
7721a0d117Sderaadt 	{  MEG(900),         GIG(2),   5, "/usr"	},
7892adb55fSderaadt 	{  MEG(512),         GIG(1),   3, "/usr/X11R6"	},
796e1f4775Sotto 	{    GIG(2),        GIG(10),  10, "/usr/local"	},
8092adb55fSderaadt 	{    GIG(1),         GIG(2),   3, "/usr/src"	},
8192adb55fSderaadt 	{    GIG(1),         GIG(2),   3, "/usr/obj"	},
826e1f4775Sotto 	{    GIG(1),       GIG(300),  45, "/home"	}
834ab111d2Sderaadt 	/* Anything beyond this leave for the user to decide */
848dde8bb6Sotto };
858dde8bb6Sotto 
868dde8bb6Sotto const struct space_allocation alloc_medium[] = {
87905e8239Sderaadt 	{  MEG(800),         GIG(2),   5, "/"		},
888dde8bb6Sotto 	{   MEG(80),       MEG(256),  10, "swap"	},
89905e8239Sderaadt 	{  MEG(900),         GIG(3),  78, "/usr"	},
90905e8239Sderaadt 	{  MEG(256),         GIG(2),   7, "/home"	}
918dde8bb6Sotto };
928dde8bb6Sotto 
938dde8bb6Sotto const struct space_allocation alloc_small[] = {
9492adb55fSderaadt 	{  MEG(700),         GIG(4),  95, "/"		},
958dde8bb6Sotto 	{    MEG(1),       MEG(256),   5, "swap"	}
968dde8bb6Sotto };
978dde8bb6Sotto 
988dde8bb6Sotto const struct space_allocation alloc_stupid[] = {
998dde8bb6Sotto 	{    MEG(1),      MEG(2048), 100, "/"		}
1008dde8bb6Sotto };
1018dde8bb6Sotto 
102b2813ff1Sderaadt #ifndef nitems
103b2813ff1Sderaadt #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
104b2813ff1Sderaadt #endif
105b2813ff1Sderaadt 
1068a862940Sderaadt const struct {
1078a862940Sderaadt 	const struct space_allocation *table;
1088a862940Sderaadt 	int sz;
1098a862940Sderaadt } alloc_table[] = {
1108dde8bb6Sotto 	{ alloc_big,	nitems(alloc_big) },
1118dde8bb6Sotto 	{ alloc_medium,	nitems(alloc_medium) },
1128dde8bb6Sotto 	{ alloc_small,	nitems(alloc_small) },
1138dde8bb6Sotto 	{ alloc_stupid,	nitems(alloc_stupid) }
114557f712bSkrw };
115557f712bSkrw 
1169fdcb4d6Skrw void	edit_parms(struct disklabel *);
1176aaa4aabSotto void	editor_resize(struct disklabel *, char *);
11834ae4198Skrw void	editor_add(struct disklabel *, char *);
1199fdcb4d6Skrw void	editor_change(struct disklabel *, char *);
1209fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *);
12134ae4198Skrw void	editor_delete(struct disklabel *, char *);
1224d812bb6Slum void	editor_help(void);
12334ae4198Skrw void	editor_modify(struct disklabel *, char *);
12434ae4198Skrw void	editor_name(struct disklabel *, char *);
125c72b5b24Smillert char	*getstring(char *, char *, char *);
126dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int);
1271f0f871dSkrw int	has_overlap(struct disklabel *);
128c72b5b24Smillert int	partition_cmp(const void *, const void *);
1290fbd3c97Skrw struct partition **sort_partitions(struct disklabel *);
130c72b5b24Smillert void	getdisktype(struct disklabel *, char *, char *);
13187023ed9Skrw void	find_bounds(struct disklabel *);
1329fdcb4d6Skrw void	set_bounds(struct disklabel *);
1330d63cfbaSjsing void	set_uid(struct disklabel *);
134c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *);
1354f3bbbf0Skrw void	mpcopy(char **, char **);
136c72b5b24Smillert int	micmp(const void *, const void *);
137c72b5b24Smillert int	mpequal(char **, char **);
138c72b5b24Smillert int	get_bsize(struct disklabel *, int);
139c72b5b24Smillert int	get_fsize(struct disklabel *, int);
140c72b5b24Smillert int	get_fstype(struct disklabel *, int);
14134ae4198Skrw int	get_mp(struct disklabel *, int);
142604d3bdeSkrw int	get_offset(struct disklabel *, int);
1439fdcb4d6Skrw int	get_size(struct disklabel *, int);
14487023ed9Skrw void	get_geometry(int, struct disklabel **);
14587023ed9Skrw void	set_geometry(struct disklabel *, struct disklabel *, struct disklabel *,
14687023ed9Skrw 	    char *);
1479fdcb4d6Skrw void	zero_partitions(struct disklabel *);
14814192793Skrw u_int64_t max_partition_size(struct disklabel *, int);
14934ae4198Skrw void	display_edit(struct disklabel *, char, u_int64_t);
15096a888c6Smillert 
1511e0ad43cSotto static u_int64_t starting_sector;
1521e0ad43cSotto static u_int64_t ending_sector;
1532d8451b0Smillert static int expert;
154fc6e9c48Sotto static int overlap;
1556fe57b42Smillert 
1566fe57b42Smillert /*
1574d4a335eSkrw  * Simple partition editor.
1586fe57b42Smillert  */
1596fe57b42Smillert int
16034ae4198Skrw editor(struct disklabel *lp, int f)
1616fe57b42Smillert {
1624f3bbbf0Skrw 	struct disklabel origlabel, lastlabel, tmplabel, label = *lp;
1637e28fb0fSderaadt 	struct disklabel *disk_geop = NULL;
16496a888c6Smillert 	struct partition *pp;
1656fe57b42Smillert 	FILE *fp;
1666fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
16734ae4198Skrw 	char **omountpoints = NULL;
1684f3bbbf0Skrw 	char **origmountpoints = NULL, **tmpmountpoints = NULL;
1697e28fb0fSderaadt 	int i, error = 0;
170bd6726faSmillert 
171bd6726faSmillert 	/* Alloc and init mount point info */
17234ae4198Skrw 	if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
1734f3bbbf0Skrw 	    !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
174bd6726faSmillert 	    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
175bd6726faSmillert 		errx(4, "out of memory");
1766fe57b42Smillert 
17796a888c6Smillert 	/* Don't allow disk type of "unknown" */
17834ae4198Skrw 	getdisktype(&label, "You need to specify a type for this disk.", specname);
1796fe57b42Smillert 
18087023ed9Skrw 	/* Get the on-disk geometries if possible */
18187023ed9Skrw 	get_geometry(f, &disk_geop);
182c33fcabaSmillert 
183d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
18487023ed9Skrw 	find_bounds(&label);
185d09f3941Smillert 
18696a888c6Smillert 	/* Make sure there is no partition overlap. */
1871f0f871dSkrw 	if (has_overlap(&label))
1886fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1896fe57b42Smillert 
19096a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
191d09f3941Smillert 	pp = &label.d_partitions[RAW_PART];
1921e0ad43cSotto 	if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) {
19396a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
19496a888c6Smillert 		if (label.d_npartitions < 3)
19596a888c6Smillert 			label.d_npartitions = 3;
19634af67a3Sotto 		DL_SETPOFFSET(pp, 0);
19734af67a3Sotto 		DL_SETPSIZE(pp, DL_GETDSIZE(&label));
19896a888c6Smillert 		pp->p_fstype = FS_UNUSED;
199ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
20096a888c6Smillert 	}
2010f820bbbSmillert 
202fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
203fc1a4cc6Sderaadt 	if (label.d_flags & D_VENDOR) {
204fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
205fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
206fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
207fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
208fc1a4cc6Sderaadt 	}
2096fe57b42Smillert #endif
2106fe57b42Smillert 
211bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
21255403f76Smillert 	if (label.d_bbsize == 0)
21355403f76Smillert 		label.d_bbsize = BBSIZE;
21455403f76Smillert 	if (label.d_sbsize == 0)
21555403f76Smillert 		label.d_sbsize = SBSIZE;
216f98aebd4Smillert 
21793160b9bSkrw 	/* Save the (U|u)ndo labels and mountpoints. */
21893160b9bSkrw 	mpcopy(origmountpoints, mountpoints);
2194f3bbbf0Skrw 	origlabel = label;
2206fe57b42Smillert 	lastlabel = label;
22134ae4198Skrw 
22234ae4198Skrw 	puts("Label editor (enter '?' for help at any prompt)");
2236fe57b42Smillert 	for (;;) {
2246fe57b42Smillert 		fputs("> ", stdout);
2256e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2266e0becc5Smillert 			putchar('\n');
2276e0becc5Smillert 			buf[0] = 'q';
2286e0becc5Smillert 			buf[1] = '\0';
2296e0becc5Smillert 		}
230260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
231260513deSmillert 			continue;
232260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2336fe57b42Smillert 
2344f3bbbf0Skrw 		if ((*cmd != 'u') && (*cmd != 'U')) {
2354f3bbbf0Skrw 			/*
2364f3bbbf0Skrw 			 * Save undo info in case the command tries to make
2374f3bbbf0Skrw 			 * changes but decides not to.
2384f3bbbf0Skrw 			 */
2394f3bbbf0Skrw 			tmplabel = lastlabel;
2404f3bbbf0Skrw 			lastlabel = label;
2414f3bbbf0Skrw 			mpcopy(tmpmountpoints, omountpoints);
2424f3bbbf0Skrw 			mpcopy(omountpoints, mountpoints);
2434f3bbbf0Skrw 		}
2446fe57b42Smillert 
2454f3bbbf0Skrw 		switch (*cmd) {
2466fe57b42Smillert 		case '?':
247ea37abd3Sderaadt 		case 'h':
2484d812bb6Slum 			editor_help();
2496fe57b42Smillert 			break;
2506fe57b42Smillert 
251557f712bSkrw 		case 'A':
252ab20a3eaSkrw 			if (ioctl(f, DIOCGPDINFO, &label) == 0) {
253ab20a3eaSkrw 				aflag = 1;
25434ae4198Skrw 				editor_allocspace(&label);
255ab20a3eaSkrw 			} else
25634ae4198Skrw 				label = lastlabel;
257557f712bSkrw 			break;
2586fe57b42Smillert 		case 'a':
25934ae4198Skrw 			editor_add(&label, arg);
26096a888c6Smillert 			break;
26196a888c6Smillert 
26296a888c6Smillert 		case 'b':
2639fdcb4d6Skrw 			set_bounds(&label);
2646fe57b42Smillert 			break;
2656fe57b42Smillert 
2666fe57b42Smillert 		case 'c':
2679fdcb4d6Skrw 			editor_change(&label, arg);
2686fe57b42Smillert 			break;
2696fe57b42Smillert 
2709afbe9eeSmillert 		case 'D':
27193160b9bSkrw 			if (ioctl(f, DIOCGPDINFO, &label) == 0) {
27271bba4ecSkrw 				dflag = 1;
27393160b9bSkrw 				for (i=0; i<MAXPARTITIONS; i++) {
27493160b9bSkrw 					free(mountpoints[i]);
27593160b9bSkrw 					mountpoints[i] = NULL;
27693160b9bSkrw 				}
27793160b9bSkrw 			} else
278cdd7eb76Smillert 				warn("unable to get default partition table");
2799afbe9eeSmillert 			break;
2809afbe9eeSmillert 
2816fe57b42Smillert 		case 'd':
28234ae4198Skrw 			editor_delete(&label, arg);
2836fe57b42Smillert 			break;
2846fe57b42Smillert 
2859afbe9eeSmillert 		case 'e':
2869fdcb4d6Skrw 			edit_parms(&label);
2879afbe9eeSmillert 			break;
2889afbe9eeSmillert 
289c33fcabaSmillert 		case 'g':
29087023ed9Skrw 			set_geometry(&label, disk_geop, lp, arg);
291c33fcabaSmillert 			break;
292c33fcabaSmillert 
2930d63cfbaSjsing 		case 'i':
2940d63cfbaSjsing 			set_uid(&label);
2950d63cfbaSjsing 			break;
2960d63cfbaSjsing 
2976fe57b42Smillert 		case 'm':
29834ae4198Skrw 			editor_modify(&label, arg);
299bd6726faSmillert 			break;
300bd6726faSmillert 
301bd6726faSmillert 		case 'n':
3025c79e1cfSkrw 			if (!fstabfile) {
303bd6726faSmillert 				fputs("This option is not valid when run "
30484d0bb16Sderaadt 				    "without the -f flag.\n", stderr);
305bd6726faSmillert 				break;
306bd6726faSmillert 			}
30734ae4198Skrw 			editor_name(&label, arg);
3086fe57b42Smillert 			break;
3096fe57b42Smillert 
3106fe57b42Smillert 		case 'p':
31134ae4198Skrw 			display_edit(&label, arg ? *arg : 0, editor_countfree(&label));
3126fe57b42Smillert 			break;
3136fe57b42Smillert 
314aff3f969Sotto 		case 'l':
31534ae4198Skrw 			display(stdout, &label, arg ? *arg : 0, 0);
316aff3f969Sotto 			break;
317aff3f969Sotto 
318508086e9Smillert 		case 'M': {
319508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
32045decb36Sderaadt 			char *pager, *comm = NULL;
321e7936562Sderaadt 			extern const u_char manpage[];
32208f8e31fSotto 			extern const int manpage_sz;
3235d12b01bSderaadt 
324489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
325508086e9Smillert 				pager = _PATH_LESS;
32608f8e31fSotto 
32745decb36Sderaadt 			if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
32845decb36Sderaadt 			    (fp = popen(comm, "w")) != NULL) {
32908f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3305d12b01bSderaadt 				pclose(fp);
331508086e9Smillert 			} else
332508086e9Smillert 				warn("unable to execute %s", pager);
333508086e9Smillert 
33445decb36Sderaadt 			free(comm);
335508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3365d12b01bSderaadt 			break;
337508086e9Smillert 		}
3385d12b01bSderaadt 
3396fe57b42Smillert 		case 'q':
34069220492Smillert 			if (donothing) {
34169220492Smillert 				puts("In no change mode, not writing label.");
3427e28fb0fSderaadt 				goto done;
34369220492Smillert 			}
344bd6726faSmillert 			/* Save mountpoint info if there is any. */
34534ae4198Skrw 			mpsave(&label);
34693160b9bSkrw 
34771bba4ecSkrw                         /*
34893160b9bSkrw 			 * If we haven't changed the original label, and it
34993160b9bSkrw 			 * wasn't a default label or an auto-allocated label,
35093160b9bSkrw 			 * there is no need to do anything before exiting. Note
35193160b9bSkrw 			 * that 'w' will reset dflag and aflag to allow 'q' to
35293160b9bSkrw 			 * exit without further questions.
35371bba4ecSkrw  			 */
354ab20a3eaSkrw 			if (!dflag && !aflag &&
355ab20a3eaSkrw 			    memcmp(lp, &label, sizeof(label)) == 0) {
356bd6726faSmillert 				puts("No label changes.");
3577e28fb0fSderaadt 				goto done;
3586fe57b42Smillert 			}
3596fe57b42Smillert 			do {
360d0e67762Smillert 				arg = getstring("Write new label?",
361d0e67762Smillert 				    "Write the modified label to disk?",
362d0e67762Smillert 				    "y");
36396a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
36496a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
365d0e67762Smillert 				if (writelabel(f, bootarea, &label) == 0) {
3666fe57b42Smillert 					*lp = label;
3677e28fb0fSderaadt 					goto done;
3686fe57b42Smillert 				}
369d0e67762Smillert 				warnx("unable to write label");
370d0e67762Smillert 			}
3717e28fb0fSderaadt 			error = 1;
3727e28fb0fSderaadt 			goto done;
3736fe57b42Smillert 			/* NOTREACHED */
3746fe57b42Smillert 			break;
3756fe57b42Smillert 
3766aaa4aabSotto 		case 'R':
377fc6e9c48Sotto 			if (aflag && !overlap)
3786aaa4aabSotto 				editor_resize(&label, arg);
3796aaa4aabSotto 			else
3806aaa4aabSotto 				fputs("Resize only implemented for auto "
381fc6e9c48Sotto 				    "allocated labels\n", stderr);
3826aaa4aabSotto 			break;
3836aaa4aabSotto 
38425f9c360Skrw 		case 'r': {
38525f9c360Skrw 			struct diskchunk *chunks;
38625f9c360Skrw 			int i;
3879fdcb4d6Skrw 			/* Display free space. */
38825f9c360Skrw 			chunks = free_chunks(&label);
38925f9c360Skrw 			for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0;
39025f9c360Skrw 			    i++)
39125f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
39225f9c360Skrw 				    "(%16llu)\n",
39325f9c360Skrw 			    	    chunks[i].start, chunks[i].stop - 1,
39425f9c360Skrw 			   	    chunks[i].stop - chunks[i].start);
39525f9c360Skrw 			fprintf(stderr, "Total free sectors: %llu.\n",
3969fdcb4d6Skrw 			    editor_countfree(&label));
397c0bdc608Smillert 		    	break;
39825f9c360Skrw 		}
399c0bdc608Smillert 
4006fe57b42Smillert 		case 's':
4016fe57b42Smillert 			if (arg == NULL) {
402c33fcabaSmillert 				arg = getstring("Filename",
4036fe57b42Smillert 				    "Name of the file to save label into.",
4046fe57b42Smillert 				    NULL);
405e97229a3Scnst 				if (arg == NULL || *arg == '\0')
4066fe57b42Smillert 					break;
4076fe57b42Smillert 			}
4086fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
4096fe57b42Smillert 				warn("cannot open %s", arg);
4106fe57b42Smillert 			} else {
41134ae4198Skrw 				display(fp, &label, 0, 1);
4126fe57b42Smillert 				(void)fclose(fp);
4136fe57b42Smillert 			}
4146fe57b42Smillert 			break;
4156fe57b42Smillert 
4164f3bbbf0Skrw 		case 'U':
41793160b9bSkrw 			/*
41893160b9bSkrw 			 * If we allow 'U' repeatedly, information would be lost. This way
41993160b9bSkrw 			 * multiple 'U's followed by 'u' would undo the 'U's.
42093160b9bSkrw 			 */
42193160b9bSkrw 			if (memcmp(&label, &origlabel, sizeof(label)) ||
42293160b9bSkrw 			    !mpequal(mountpoints, origmountpoints)) {
4234f3bbbf0Skrw 				tmplabel = label;
4244f3bbbf0Skrw 				label = origlabel;
4254f3bbbf0Skrw 				lastlabel = tmplabel;
4264f3bbbf0Skrw 				mpcopy(tmpmountpoints, mountpoints);
4274f3bbbf0Skrw 				mpcopy(mountpoints, origmountpoints);
4284f3bbbf0Skrw 				mpcopy(omountpoints, tmpmountpoints);
4294f3bbbf0Skrw 			}
43093160b9bSkrw 			puts("Original label and mount points restored.");
4314f3bbbf0Skrw 			break;
4324f3bbbf0Skrw 
4336fe57b42Smillert 		case 'u':
4346fe57b42Smillert 			tmplabel = label;
4356fe57b42Smillert 			label = lastlabel;
4366fe57b42Smillert 			lastlabel = tmplabel;
4374f3bbbf0Skrw 			mpcopy(tmpmountpoints, mountpoints);
438bd6726faSmillert 			mpcopy(mountpoints, omountpoints);
4394f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4406fe57b42Smillert 			puts("Last change undone.");
4416fe57b42Smillert 			break;
4426fe57b42Smillert 
443040947cfSmillert 		case 'w':
444bd6726faSmillert 			if (donothing)  {
445040947cfSmillert 				puts("In no change mode, not writing label.");
446bd6726faSmillert 				break;
447bd6726faSmillert 			}
44893160b9bSkrw 
44941f684b9Skrw 			/* Write label to disk. */
45041f684b9Skrw 			if (writelabel(f, bootarea, &label) != 0)
451040947cfSmillert 				warnx("unable to write label");
45271bba4ecSkrw 			else {
453ab20a3eaSkrw 				dflag = aflag = 0;
4545af08e9cSmillert 				*lp = label;
45571bba4ecSkrw 			}
456040947cfSmillert 			break;
457040947cfSmillert 
4582d8451b0Smillert 		case 'X':
4592d8451b0Smillert 			expert = !expert;
4602d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
4612d8451b0Smillert 			    "Exiting");
4622d8451b0Smillert 			break;
4632d8451b0Smillert 
4646fe57b42Smillert 		case 'x':
4657e28fb0fSderaadt 			goto done;
4666fe57b42Smillert 			break;
4676fe57b42Smillert 
4689afbe9eeSmillert 		case 'z':
4699fdcb4d6Skrw 			zero_partitions(&label);
4706fe57b42Smillert 			break;
4716fe57b42Smillert 
4729afbe9eeSmillert 		case '\n':
4736fe57b42Smillert 			break;
4746fe57b42Smillert 
4756fe57b42Smillert 		default:
4766fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4776fe57b42Smillert 			break;
4786fe57b42Smillert 		}
4794f3bbbf0Skrw 
4804f3bbbf0Skrw 		/*
4814f3bbbf0Skrw 		 * If no changes were made to label or mountpoints, then
4824f3bbbf0Skrw 		 * restore undo info.
4834f3bbbf0Skrw 		 */
4844f3bbbf0Skrw 		if (memcmp(&label, &lastlabel, sizeof(label)) == 0 &&
48593160b9bSkrw 		    (mpequal(mountpoints, omountpoints))) {
4864f3bbbf0Skrw 			lastlabel = tmplabel;
4874f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4884f3bbbf0Skrw 		}
4896fe57b42Smillert 	}
4907e28fb0fSderaadt done:
4917e28fb0fSderaadt 	free(omountpoints);
4927e28fb0fSderaadt 	free(origmountpoints);
4937e28fb0fSderaadt 	free(tmpmountpoints);
4947e28fb0fSderaadt 	if (disk_geop)
4957e28fb0fSderaadt 		free(disk_geop);
4967e28fb0fSderaadt 	return(error);
4976fe57b42Smillert }
4986fe57b42Smillert 
4998dde8bb6Sotto int64_t
5008dde8bb6Sotto getphysmem(void)
5018dde8bb6Sotto {
5028dde8bb6Sotto 	int64_t physmem;
5038dde8bb6Sotto 	size_t sz = sizeof(physmem);
5048dde8bb6Sotto 	int mib[] = { CTL_HW, HW_PHYSMEM64 };
5058dde8bb6Sotto 	if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1)
5068dde8bb6Sotto 		errx(4, "can't get mem size");
5078dde8bb6Sotto 	return physmem;
5088dde8bb6Sotto }
5098dde8bb6Sotto 
5106fe57b42Smillert /*
511557f712bSkrw  * Allocate all disk space according to standard recommendations for a
512557f712bSkrw  * root disk.
513557f712bSkrw  */
514557f712bSkrw void
5158dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
516557f712bSkrw {
5178dde8bb6Sotto 	struct disklabel *lp, label;
5188dde8bb6Sotto 	struct space_allocation *alloc;
51934ae4198Skrw 	struct space_allocation *ap;
520557f712bSkrw 	struct partition *pp;
52134ae4198Skrw 	struct diskchunk *chunks;
52234ae4198Skrw 	daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs;
52334ae4198Skrw 	char **partmp;
524*a49bdda8Skrw 	int i, j, lastalloc, index = 0, fragsize, partno;
5258dde8bb6Sotto 	int64_t physmem;
5268dde8bb6Sotto 
52734ae4198Skrw 	/* How big is the OpenBSD portion of the disk?  */
5288dde8bb6Sotto 	find_bounds(lp_org);
529557f712bSkrw 
530fc6e9c48Sotto 	overlap = 0;
531fc6e9c48Sotto 	for (i = 0;  i < MAXPARTITIONS; i++) {
532fc6e9c48Sotto 		daddr64_t psz, pstart, pend;
533fc6e9c48Sotto 
534fc6e9c48Sotto 		pp = &lp_org->d_partitions[i];
535fc6e9c48Sotto 		psz = DL_GETPSIZE(pp);
536fc6e9c48Sotto 		pstart = DL_GETPOFFSET(pp);
537fc6e9c48Sotto 		pend = pstart + psz;
538fc6e9c48Sotto 		if (i != RAW_PART && psz != 0 &&
539fc6e9c48Sotto 		    ((pstart >= starting_sector && pstart <= ending_sector) ||
540fc6e9c48Sotto 		    (pend > starting_sector && pend < ending_sector))) {
541fc6e9c48Sotto 			overlap = 1;
542fc6e9c48Sotto 			break;
543fc6e9c48Sotto 		}
544fc6e9c48Sotto 	}
545fc6e9c48Sotto 
546fc6e9c48Sotto 	physmem = getphysmem() / lp_org->d_secsize;
547fc6e9c48Sotto 
5488dde8bb6Sotto 	cylsecs = lp_org->d_secpercyl;
5498dde8bb6Sotto again:
5508dde8bb6Sotto 	lp = &label;
5513d98fc8cSkrw 	for (i=0; i<MAXPARTITIONS; i++) {
5523d98fc8cSkrw 		free(mountpoints[i]);
5533d98fc8cSkrw 		mountpoints[i] = NULL;
5543d98fc8cSkrw 	}
5558dde8bb6Sotto 	memcpy(lp, lp_org, sizeof(struct disklabel));
5560a7398ceSderaadt 	lp->d_npartitions = MAXPARTITIONS;
5578dde8bb6Sotto 	lastalloc = alloc_table[index].sz;
5588dde8bb6Sotto 	alloc = malloc(lastalloc * sizeof(struct space_allocation));
5598dde8bb6Sotto 	if (alloc == NULL)
5608dde8bb6Sotto 		errx(4, "out of memory");
5618dde8bb6Sotto 	memcpy(alloc, alloc_table[index].table,
5628dde8bb6Sotto 	    lastalloc * sizeof(struct space_allocation));
5638dde8bb6Sotto 
5648dde8bb6Sotto 	/* bump max swap based on phys mem, little physmem gets 2x swap */
5658dde8bb6Sotto 	if (index == 0) {
5668dde8bb6Sotto 		if (physmem < 256LL * 1024 * 1024 / lp->d_secsize)
5678dde8bb6Sotto 			alloc[1].maxsz = 2 * physmem;
5688dde8bb6Sotto 		else
5698dde8bb6Sotto 			alloc[1].maxsz += physmem;
5708dde8bb6Sotto 		/* bump max /var to make room for 2 crash dumps */
5718dde8bb6Sotto 		alloc[3].maxsz += 2 * physmem;
5728dde8bb6Sotto 	}
5738dde8bb6Sotto 
57434ae4198Skrw 	xtrasecs = totsecs = editor_countfree(lp);
575557f712bSkrw 
57634ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
5775f3e1104Skrw 		alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz);
5785f3e1104Skrw 		alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz);
57934ae4198Skrw 		if (xtrasecs > alloc[i].minsz)
58034ae4198Skrw 			xtrasecs -= alloc[i].minsz;
58134ae4198Skrw 		else
58234ae4198Skrw 			xtrasecs = 0;
583557f712bSkrw 	}
584557f712bSkrw 
58534ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
58634ae4198Skrw 		/* Find next available partition. */
58734ae4198Skrw 		for (j = 0;  j < MAXPARTITIONS; j++)
58834ae4198Skrw 			if (DL_GETPSIZE(&lp->d_partitions[j]) == 0)
58934ae4198Skrw 				break;
59034ae4198Skrw 		if (j == MAXPARTITIONS)
59134ae4198Skrw 			return;
592*a49bdda8Skrw 		partno = j;
59334ae4198Skrw 		pp = &lp->d_partitions[j];
59434ae4198Skrw 		partmp = &mountpoints[j];
59534ae4198Skrw 		ap = &alloc[i];
596557f712bSkrw 
59734ae4198Skrw 		/* Figure out the size of the partition. */
59834ae4198Skrw 		if (i == lastalloc - 1) {
59934ae4198Skrw 			if (totsecs > ap->maxsz)
60034ae4198Skrw 				secs = ap->maxsz;
601557f712bSkrw 			else
6025f3e1104Skrw 				secs = totsecs;
6031f5ea549Skrw #ifdef SUN_CYLCHECK
6041f5ea549Skrw 			goto cylinderalign;
6051f5ea549Skrw #endif
606557f712bSkrw 		} else {
60734ae4198Skrw 			secs = ap->minsz;
6085f3e1104Skrw 			if (xtrasecs > 0)
60934ae4198Skrw 				secs += (xtrasecs / 100) * ap->rate;
61034ae4198Skrw 			if (secs > ap->maxsz)
61134ae4198Skrw 				secs = ap->maxsz;
6121f5ea549Skrw #ifdef SUN_CYLCHECK
6131f5ea549Skrw cylinderalign:
6145f3e1104Skrw 			secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
6151f5ea549Skrw #endif
6165f3e1104Skrw 			totsecs -= secs;
6171f5ea549Skrw #ifdef SUN_CYLCHECK
6185f3e1104Skrw 			while (totsecs < 0) {
6195f3e1104Skrw 				secs -= cylsecs;
6205f3e1104Skrw 				totsecs += cylsecs;
621557f712bSkrw 			}
6221f5ea549Skrw #endif
623557f712bSkrw 		}
62434ae4198Skrw 
62534ae4198Skrw 		/* Find largest chunk of free space. */
62634ae4198Skrw 		chunks = free_chunks(lp);
62734ae4198Skrw 		chunkstart = 0;
62834ae4198Skrw 		chunksize = 0;
62934ae4198Skrw 		for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++)
63034ae4198Skrw 			if ((chunks[j].stop - chunks[j].start) > chunksize) {
63134ae4198Skrw 				chunkstart = chunks[j].start;
63234ae4198Skrw 				chunksize = chunks[j].stop - chunks[j].start;
633557f712bSkrw 			}
63434ae4198Skrw #ifdef SUN_CYLCHECK
63534ae4198Skrw 		if (lp->d_flags & D_VENDOR) {
63634ae4198Skrw 			/* Align chunk to cylinder boundaries. */
63734ae4198Skrw 			chunksize -= chunksize % cylsecs;
6386ab0bb66Skrw 			chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) *
6396ab0bb66Skrw 			    cylsecs;
64034ae4198Skrw 		}
64134ae4198Skrw #endif
64234ae4198Skrw 		/* See if partition can fit into chunk. */
64334ae4198Skrw 		if (secs > chunksize) {
64434ae4198Skrw 			totsecs += secs - chunksize;
64534ae4198Skrw 			secs = chunksize;
64634ae4198Skrw 		}
64734ae4198Skrw 		if (secs < ap->minsz) {
6488dde8bb6Sotto 			/* It did not work out, try next strategy */
6498dde8bb6Sotto 			free(alloc);
6508dde8bb6Sotto 			if (++index < nitems(alloc_table))
6518dde8bb6Sotto 				goto again;
6528dde8bb6Sotto 			else
6538dde8bb6Sotto 				return;
654557f712bSkrw 		}
65534ae4198Skrw 
65634ae4198Skrw 		/* Everything seems ok so configure the partition. */
6575f3e1104Skrw 		DL_SETPSIZE(pp, secs);
65834ae4198Skrw 		DL_SETPOFFSET(pp, chunkstart);
6596e312d52Sotto 		fragsize = 2048;
660c88f83bdSotto 		if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024)
661c88f83bdSotto 			fragsize *= 2;
662c88f83bdSotto 		if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024)
663c88f83bdSotto 			fragsize *= 2;
664557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__)
665557f712bSkrw 		/* can't boot from > 8k boot blocks */
666557f712bSkrw 		pp->p_fragblock =
6676e312d52Sotto 		    DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8);
668557f712bSkrw #else
6696e312d52Sotto 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
670557f712bSkrw #endif
671557f712bSkrw 		pp->p_cpg = 1;
67234ae4198Skrw 		if (ap->mp[0] != '/')
67334ae4198Skrw 			pp->p_fstype = FS_SWAP;
67434ae4198Skrw 		else {
67534ae4198Skrw 			pp->p_fstype = FS_BSDFFS;
676*a49bdda8Skrw 			get_bsize(lp, partno);
67734ae4198Skrw 			free(*partmp);
67834ae4198Skrw 			if ((*partmp = strdup(ap->mp)) == NULL)
679557f712bSkrw 				errx(4, "out of memory");
680557f712bSkrw 		}
681557f712bSkrw 	}
682557f712bSkrw 
6838dde8bb6Sotto 	free(alloc);
6848dde8bb6Sotto 	memcpy(lp_org, lp, sizeof(struct disklabel));
685557f712bSkrw }
686557f712bSkrw 
687557f712bSkrw /*
6886aaa4aabSotto  * Resize a partition, moving all subsequent partitions
6896aaa4aabSotto  */
6906aaa4aabSotto void
6916aaa4aabSotto editor_resize(struct disklabel *lp, char *p)
6926aaa4aabSotto {
6936aaa4aabSotto 	struct disklabel label;
6946aaa4aabSotto 	struct partition *pp, *prev;
6956aaa4aabSotto 	daddr64_t secs, sz, off;
6966aaa4aabSotto #ifdef SUN_CYLCHECK
6976aaa4aabSotto 	daddr64_t cylsecs;
6986aaa4aabSotto #endif
6996aaa4aabSotto 	int partno, i;
7006aaa4aabSotto 
7016aaa4aabSotto 	label = *lp;
7026aaa4aabSotto 
7036aaa4aabSotto 	/* Change which partition? */
7046aaa4aabSotto 	if (p == NULL) {
7056aaa4aabSotto 		p = getstring("partition to resize",
7066aaa4aabSotto 		    "The letter of the partition to name, a - p.", NULL);
7076aaa4aabSotto 	}
7086aaa4aabSotto 	if (p == NULL) {
7096aaa4aabSotto 		fputs("Command aborted\n", stderr);
7106aaa4aabSotto 		return;
7116aaa4aabSotto 	}
7126aaa4aabSotto 	partno = p[0] - 'a';
7136aaa4aabSotto         if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
7146aaa4aabSotto 		fprintf(stderr, "Partition must be between 'a' and '%c' "
7156aaa4aabSotto 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
7166aaa4aabSotto 		return;
7176aaa4aabSotto 	}
7186aaa4aabSotto 
7196aaa4aabSotto 	pp = &label.d_partitions[partno];
720fc6e9c48Sotto 	sz = DL_GETPSIZE(pp);
721fc6e9c48Sotto 	if (sz == 0) {
722fc6e9c48Sotto 		fputs("No such partition\n", stderr);
723fc6e9c48Sotto 		return;
724fc6e9c48Sotto 	}
725fc6e9c48Sotto 	if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) {
726fc6e9c48Sotto 		fputs("Cannot resize spoofed partition\n", stderr);
727fc6e9c48Sotto 		return;
728fc6e9c48Sotto 	}
7296aaa4aabSotto 	secs = getuint(lp, "resize", "amount to grow (+) or shrink (-)",
730fc6e9c48Sotto 	    0, editor_countfree(lp), 0, DO_CONVERSIONS);
7316aaa4aabSotto 
732fc6e9c48Sotto 	if (secs == 0 || secs == -1) {
7336aaa4aabSotto 		fputs("Command aborted\n", stderr);
7346aaa4aabSotto 		return;
7356aaa4aabSotto 	}
7366aaa4aabSotto 
7376aaa4aabSotto #ifdef SUN_CYLCHECK
7386aaa4aabSotto 	cylsecs = lp->d_secpercyl;
7396aaa4aabSotto 	if (secs > 0)
7406aaa4aabSotto 		secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
7416aaa4aabSotto 	else
7426aaa4aabSotto 		secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs;
7436aaa4aabSotto #endif
7446aaa4aabSotto 	if (DL_GETPOFFSET(pp) + sz + secs > ending_sector) {
7456aaa4aabSotto 		fputs("Amount too big\n", stderr);
7466aaa4aabSotto 		return;
7476aaa4aabSotto 	}
7486aaa4aabSotto 	if (sz + secs < 0) {
7496aaa4aabSotto 		fputs("Amount too small\n", stderr);
7506aaa4aabSotto 		return;
7516aaa4aabSotto 	}
7526aaa4aabSotto 
7536aaa4aabSotto 	DL_SETPSIZE(pp, sz + secs);
7546aaa4aabSotto 
7556aaa4aabSotto 	/*
7566aaa4aabSotto 	 * Pack partitions above the resized partition, leaving unused
7576aaa4aabSotto 	 * partions alone.
7586aaa4aabSotto 	 */
7596aaa4aabSotto 	prev = pp;
7606aaa4aabSotto 	for (i = partno + 1; i < MAXPARTITIONS; i++) {
7616aaa4aabSotto 		if (i == RAW_PART)
7626aaa4aabSotto 			continue;
763fc6e9c48Sotto 		pp = &label.d_partitions[i];
764fc6e9c48Sotto 		if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP)
765fc6e9c48Sotto 			continue;
766fc6e9c48Sotto 		sz = DL_GETPSIZE(pp);
7676aaa4aabSotto 		if (sz == 0)
7686aaa4aabSotto 			continue;
7696aaa4aabSotto 
7706aaa4aabSotto 		off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
7716aaa4aabSotto 
7726aaa4aabSotto 		if (off < ending_sector) {
7736aaa4aabSotto 			DL_SETPOFFSET(pp, off);
7746aaa4aabSotto 			if (off + DL_GETPSIZE(pp) > ending_sector) {
7756aaa4aabSotto 				DL_SETPSIZE(pp, ending_sector - off);
7766aaa4aabSotto 				fprintf(stderr,
7776aaa4aabSotto 				    "Partition %c shrunk to make room\n",
7786aaa4aabSotto 				    i + 'a');
7796aaa4aabSotto 			}
7806aaa4aabSotto 		} else {
7816aaa4aabSotto 			fputs("No room left for all partitions\n", stderr);
7826aaa4aabSotto 			return;
7836aaa4aabSotto 		}
7846aaa4aabSotto 		prev = pp;
7856aaa4aabSotto 	}
7866aaa4aabSotto 	*lp = label;
7876aaa4aabSotto }
7886aaa4aabSotto 
7896aaa4aabSotto /*
7906fe57b42Smillert  * Add a new partition.
7916fe57b42Smillert  */
7926fe57b42Smillert void
79334ae4198Skrw editor_add(struct disklabel *lp, char *p)
7946fe57b42Smillert {
79596a888c6Smillert 	struct partition *pp;
79696a888c6Smillert 	struct diskchunk *chunks;
7975caa08b2Skrw 	char buf[2];
7986e312d52Sotto 	int i, partno, fragsize;
799f8ab7229Schl 	u_int64_t freesectors, new_offset, new_size;
8009fdcb4d6Skrw 
8019fdcb4d6Skrw 	freesectors = editor_countfree(lp);
8026fe57b42Smillert 
8036fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
804fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
8059fdcb4d6Skrw 	if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) {
806fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
807fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
808fc1a4cc6Sderaadt 		    stderr);
809fc1a4cc6Sderaadt 		return;
810fc1a4cc6Sderaadt 	}
8118390cf28Smillert #endif
8129fdcb4d6Skrw 	if (freesectors == 0) {
8136fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
8146fe57b42Smillert 		    stderr);
8156fe57b42Smillert 		return;
8166fe57b42Smillert 	}
8176fe57b42Smillert 
8185caa08b2Skrw 	if (p == NULL) {
8195caa08b2Skrw 		/*
8205caa08b2Skrw 		 * Use the first unused partition that is not 'c' as the
8215caa08b2Skrw 		 * default partition in the prompt string.
8225caa08b2Skrw 		 */
8235caa08b2Skrw 		pp = &lp->d_partitions[0];
8245caa08b2Skrw 		buf[0] = buf[1] = '\0';
8255caa08b2Skrw 		for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) {
8265caa08b2Skrw 			if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) {
8275caa08b2Skrw 				buf[0] = partno + 'a';
8285caa08b2Skrw 				p = &buf[0];
8296fe57b42Smillert 				break;
8306fe57b42Smillert 			}
8315caa08b2Skrw 		}
832c33fcabaSmillert 		p = getstring("partition",
8336fe57b42Smillert 		    "The letter of the new partition, a - p.", p);
8346fe57b42Smillert 	}
8355caa08b2Skrw 	if (p == NULL) {
8365caa08b2Skrw 		fputs("Command aborted\n", stderr);
8375caa08b2Skrw 		return;
8385caa08b2Skrw 	}
8395caa08b2Skrw 	partno = p[0] - 'a';
8405caa08b2Skrw 	if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) {
8415caa08b2Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
8425caa08b2Skrw 		    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
8435caa08b2Skrw 		return;
8445caa08b2Skrw 	}
8455caa08b2Skrw 	pp = &lp->d_partitions[partno];
8465caa08b2Skrw 
8475caa08b2Skrw 	if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) {
8485caa08b2Skrw 		fprintf(stderr, "Partition '%c' exists.  Delete it first.\n",
8495caa08b2Skrw 		    p[0]);
8505caa08b2Skrw 		return;
8516fe57b42Smillert 	}
85296a888c6Smillert 
853caf41f96Skrw 	/*
854caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
855855d4e83Ssobrado 	 * zero'ed to avoid inadvertent overlaps.
856caf41f96Skrw 	 */
857caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
858caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
85996a888c6Smillert 
86089f4601dSkrw 	/* Make sure selected partition is zero'd too. */
86189f4601dSkrw 	memset(pp, 0, sizeof(*pp));
86215c15d8aSkrw 	chunks = free_chunks(lp);
86315c15d8aSkrw 
86415c15d8aSkrw 	/*
86515c15d8aSkrw 	 * Since we know there's free space, there must be at least one
86615c15d8aSkrw 	 * chunk. So find the largest chunk and assume we want to add the
86715c15d8aSkrw 	 * partition in that free space.
86815c15d8aSkrw 	 */
86915c15d8aSkrw 	new_size = new_offset = 0;
87015c15d8aSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
87115c15d8aSkrw 		if (chunks[i].stop - chunks[i].start > new_size) {
87215c15d8aSkrw 		    new_size = chunks[i].stop - chunks[i].start;
87315c15d8aSkrw 		    new_offset = chunks[i].start;
87415c15d8aSkrw 		}
87515c15d8aSkrw 	}
8761e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
8771e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
87896a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
879c88f83bdSotto 	pp->p_cpg = 1;
880c88f83bdSotto 
881c88f83bdSotto 	if (get_offset(lp, partno) == 0 &&
882c88f83bdSotto 	    get_size(lp, partno) == 0) {
8836e312d52Sotto 		fragsize = 2048;
884c88f83bdSotto 		new_size = DL_GETPSIZE(pp) * lp->d_secsize;
885c88f83bdSotto 		if (new_size > 128ULL * 1024 * 1024 * 1024)
886c88f83bdSotto 			fragsize *= 2;
887c88f83bdSotto 		if (new_size > 512ULL * 1024 * 1024 * 1024)
888c88f83bdSotto 			fragsize *= 2;
8894a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__)
890d98d4df7Stedu 		/* can't boot from > 8k boot blocks */
891ddfcbf38Sotto 		pp->p_fragblock =
8926e312d52Sotto 		    DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8);
893d98d4df7Stedu #else
8946e312d52Sotto 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
895d98d4df7Stedu #endif
896c88f83bdSotto 		if (get_fstype(lp, partno) == 0 &&
89734ae4198Skrw 		    get_mp(lp, partno) == 0 &&
898a4c87e64Skrw 		    get_fsize(lp, partno) == 0  &&
899a4c87e64Skrw 		    get_bsize(lp, partno) == 0)
90096a888c6Smillert 			return;
901c88f83bdSotto 	}
902a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
903a4c87e64Skrw 	DL_SETPSIZE(pp, 0);
9046fe57b42Smillert }
9056fe57b42Smillert 
9066fe57b42Smillert /*
907bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
908bd6726faSmillert  */
909bd6726faSmillert void
91034ae4198Skrw editor_name(struct disklabel *lp, char *p)
911bd6726faSmillert {
912bd6726faSmillert 	struct partition *pp;
913bd6726faSmillert 	int partno;
914bd6726faSmillert 
915bd6726faSmillert 	/* Change which partition? */
916bd6726faSmillert 	if (p == NULL) {
917c33fcabaSmillert 		p = getstring("partition to name",
918bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
919bd6726faSmillert 	}
920bd6726faSmillert 	if (p == NULL) {
921bd6726faSmillert 		fputs("Command aborted\n", stderr);
922bd6726faSmillert 		return;
923bd6726faSmillert 	}
924bd6726faSmillert 	partno = p[0] - 'a';
9256c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9266c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9276c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
928bd6726faSmillert 		return;
92966df1f0cSkrw 	}
93066df1f0cSkrw 	pp = &lp->d_partitions[partno];
93166df1f0cSkrw 
93266df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
93366df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
934bd6726faSmillert 		return;
935bd6726faSmillert 	}
936bd6726faSmillert 
937bd6726faSmillert 	/* Not all fstypes can be named */
938bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
939bd387921Stodd 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER ||
940bd387921Stodd 	    pp->p_fstype == FS_RAID) {
941bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
942baa55472Smillert 		    fstypenames[lp->d_partitions[partno].p_fstype]);
943bd6726faSmillert 		return;
944bd6726faSmillert 	}
945bd6726faSmillert 
94634ae4198Skrw 	get_mp(lp, partno);
947bd6726faSmillert }
948bd6726faSmillert 
949bd6726faSmillert /*
9506fe57b42Smillert  * Change an existing partition.
9516fe57b42Smillert  */
9526fe57b42Smillert void
95334ae4198Skrw editor_modify(struct disklabel *lp, char *p)
9546fe57b42Smillert {
9556fe57b42Smillert 	struct partition origpart, *pp;
956f8ab7229Schl 	int partno;
9576fe57b42Smillert 
9586fe57b42Smillert 	/* Change which partition? */
9596fe57b42Smillert 	if (p == NULL) {
960c33fcabaSmillert 		p = getstring("partition to modify",
9616fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
9626fe57b42Smillert 	}
96396a888c6Smillert 	if (p == NULL) {
96496a888c6Smillert 		fputs("Command aborted\n", stderr);
96596a888c6Smillert 		return;
96696a888c6Smillert 	}
9676fe57b42Smillert 	partno = p[0] - 'a';
9686c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9696c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9706c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
9716fe57b42Smillert 		return;
97266df1f0cSkrw 	}
97366df1f0cSkrw 	pp = &lp->d_partitions[partno];
97466df1f0cSkrw 
97566df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
97666df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
9776fe57b42Smillert 		return;
9786fe57b42Smillert 	}
9796fe57b42Smillert 
98066df1f0cSkrw 	origpart = *pp;
98166df1f0cSkrw 
982a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
983a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
984a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
98534ae4198Skrw 	    get_mp(lp, partno) == 0 &&
986a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
987a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
98896a888c6Smillert 		return;
9896fe57b42Smillert 
990a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
991a4c87e64Skrw 	*pp = origpart;
9926fe57b42Smillert }
9936fe57b42Smillert 
9946fe57b42Smillert /*
9956fe57b42Smillert  * Delete an existing partition.
9966fe57b42Smillert  */
9976fe57b42Smillert void
99834ae4198Skrw editor_delete(struct disklabel *lp, char *p)
9996fe57b42Smillert {
100066df1f0cSkrw 	struct partition *pp;
1001135c90d1Skrw 	int partno;
10026fe57b42Smillert 
10036fe57b42Smillert 	if (p == NULL) {
1004c33fcabaSmillert 		p = getstring("partition to delete",
1005945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
1006945ae268Smillert 		    NULL);
10076fe57b42Smillert 	}
100896a888c6Smillert 	if (p == NULL) {
100996a888c6Smillert 		fputs("Command aborted\n", stderr);
101096a888c6Smillert 		return;
101196a888c6Smillert 	}
1012945ae268Smillert 	if (p[0] == '*') {
10139fdcb4d6Skrw 		zero_partitions(lp);
1014945ae268Smillert 		return;
1015945ae268Smillert 	}
1016135c90d1Skrw 	partno = p[0] - 'a';
1017135c90d1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10186c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10196c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
102033262abfSmiod 		return;
102166df1f0cSkrw 	}
1022135c90d1Skrw 	pp = &lp->d_partitions[partno];
102366df1f0cSkrw 
102466df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
102566df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
102633262abfSmiod 		return;
102766df1f0cSkrw 	}
102866df1f0cSkrw 
10296fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
1030135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
103134ae4198Skrw 	free(mountpoints[partno]);
103234ae4198Skrw 	mountpoints[partno] = NULL;
10336fe57b42Smillert }
10346fe57b42Smillert 
10356fe57b42Smillert /*
10366fe57b42Smillert  * Change the size of an existing partition.
10376fe57b42Smillert  */
10386fe57b42Smillert void
10399fdcb4d6Skrw editor_change(struct disklabel *lp, char *p)
10406fe57b42Smillert {
10414b9a3bdaSmillert 	struct partition *pp;
104266df1f0cSkrw 	int partno;
10436fe57b42Smillert 
10446fe57b42Smillert 	if (p == NULL) {
1045c33fcabaSmillert 		p = getstring("partition to change size",
10466fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
10476fe57b42Smillert 	}
104896a888c6Smillert 	if (p == NULL) {
104996a888c6Smillert 		fputs("Command aborted\n", stderr);
105096a888c6Smillert 		return;
105196a888c6Smillert 	}
10526fe57b42Smillert 	partno = p[0] - 'a';
10536c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10546c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10556c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
10566fe57b42Smillert 		return;
10576fe57b42Smillert 	}
10584b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
10596fe57b42Smillert 
106066df1f0cSkrw 	if (DL_GETPSIZE(pp) == 0) {
106166df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
106266df1f0cSkrw 		return;
106366df1f0cSkrw 	}
106466df1f0cSkrw 
106514192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
106614192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
106714192793Skrw 	    p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno));
10687da73705Skrw 
106959ccf790Skrw 	/* Get new size */
10709fdcb4d6Skrw 	get_size(lp, partno);
10716fe57b42Smillert }
10726fe57b42Smillert 
10736fe57b42Smillert /*
10746fe57b42Smillert  * Sort the partitions based on starting offset.
10756fe57b42Smillert  * This assumes there can be no overlap.
10766fe57b42Smillert  */
10776fe57b42Smillert int
10788809fabbSderaadt partition_cmp(const void *e1, const void *e2)
10796fe57b42Smillert {
10806fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10816fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10821e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
10831e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
10846fe57b42Smillert 
10851e0ad43cSotto 	if (o1 < o2)
1086651d5bd9Sotto 		return -1;
10871e0ad43cSotto 	else if (o1 > o2)
1088651d5bd9Sotto 		return 1;
1089651d5bd9Sotto 	else
1090651d5bd9Sotto 		return 0;
10916fe57b42Smillert }
10926fe57b42Smillert 
10936fe57b42Smillert char *
10948809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval)
10956fe57b42Smillert {
10966fe57b42Smillert 	static char buf[BUFSIZ];
10976fe57b42Smillert 	int n;
10986fe57b42Smillert 
10996fe57b42Smillert 	buf[0] = '\0';
11006fe57b42Smillert 	do {
11016fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
11026e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1103260513deSmillert 			buf[0] = '\0';
110496a888c6Smillert 			if (feof(stdin)) {
110524c6582eSmillert 				clearerr(stdin);
110696a888c6Smillert 				putchar('\n');
110796a888c6Smillert 				return(NULL);
110896a888c6Smillert 			}
11096e0becc5Smillert 		}
11106fe57b42Smillert 		n = strlen(buf);
11116fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11126fe57b42Smillert 			buf[--n] = '\0';
11136fe57b42Smillert 		if (buf[0] == '?')
11146fe57b42Smillert 			puts(helpstring);
11154fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
11164fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
11176fe57b42Smillert 	} while (buf[0] == '?');
11186fe57b42Smillert 
11196fe57b42Smillert 	return(&buf[0]);
11206fe57b42Smillert }
11216fe57b42Smillert 
11226fe57b42Smillert /*
11231e0ad43cSotto  * Returns ULLONG_MAX on error
112424a2c1a4Smillert  * Usually only called by helper functions.
11256fe57b42Smillert  */
11261e0ad43cSotto u_int64_t
1127dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring,
11281e0ad43cSotto     u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags)
11296fe57b42Smillert {
11306fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
11311e0ad43cSotto 	u_int64_t rval = oval;
11326fe57b42Smillert 	size_t n;
11336fe57b42Smillert 	int mult = 1;
113414cc915fSmillert 	double d, percent = 1.0;
11356fe57b42Smillert 
11364b9a3bdaSmillert 	/* We only care about the remainder */
11374b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
11384b9a3bdaSmillert 
11396fe57b42Smillert 	buf[0] = '\0';
11406fe57b42Smillert 	do {
11411e0ad43cSotto 		printf("%s: [%llu] ", prompt, oval);
11426e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11436e0becc5Smillert 			buf[0] = '\0';
114496a888c6Smillert 			if (feof(stdin)) {
114524c6582eSmillert 				clearerr(stdin);
114696a888c6Smillert 				putchar('\n');
11471e0ad43cSotto 				return(ULLONG_MAX - 1);
114896a888c6Smillert 			}
11496e0becc5Smillert 		}
11506fe57b42Smillert 		n = strlen(buf);
11516fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11526fe57b42Smillert 			buf[--n] = '\0';
11536fe57b42Smillert 		if (buf[0] == '?')
11546fe57b42Smillert 			puts(helpstring);
11556fe57b42Smillert 	} while (buf[0] == '?');
11566fe57b42Smillert 
11576fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11586fe57b42Smillert 		rval = maxval;
11596fe57b42Smillert 	} else {
11606fe57b42Smillert 		/* deal with units */
11616fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11626fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
116396a888c6Smillert 				switch (tolower(buf[n-1])) {
11646fe57b42Smillert 
11656fe57b42Smillert 				case 'c':
11666fe57b42Smillert 					mult = lp->d_secpercyl;
11676fe57b42Smillert 					buf[--n] = '\0';
11686fe57b42Smillert 					break;
11696fe57b42Smillert 				case 'b':
11706fe57b42Smillert 					mult = -lp->d_secsize;
11716fe57b42Smillert 					buf[--n] = '\0';
11726fe57b42Smillert 					break;
11736fe57b42Smillert 				case 'k':
117450c0f47aSkrw 					if (lp->d_secsize > 1024)
117550c0f47aSkrw 						mult = -lp->d_secsize / 1024;
117650c0f47aSkrw 					else
11776fe57b42Smillert 						mult = 1024 / lp->d_secsize;
11786fe57b42Smillert 					buf[--n] = '\0';
11796fe57b42Smillert 					break;
11806fe57b42Smillert 				case 'm':
11816fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
11826fe57b42Smillert 					buf[--n] = '\0';
11836fe57b42Smillert 					break;
11841a51a1eeSmillert 				case 'g':
11851a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
11861a51a1eeSmillert 					buf[--n] = '\0';
11871a51a1eeSmillert 					break;
118814cc915fSmillert 				case '%':
118914cc915fSmillert 					buf[--n] = '\0';
119014cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
11911e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
11921e0ad43cSotto 					    DL_GETDSIZE(lp));
119314cc915fSmillert 					break;
119414cc915fSmillert 				case '&':
119514cc915fSmillert 					buf[--n] = '\0';
119614cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
11971e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
119814cc915fSmillert 					    maxval);
119914cc915fSmillert 					break;
12006fe57b42Smillert 				}
120196a888c6Smillert 			}
12026fe57b42Smillert 
12036fe57b42Smillert 			/* Did they give us an operator? */
12046fe57b42Smillert 			p = &buf[0];
12056fe57b42Smillert 			if (*p == '+' || *p == '-')
12066fe57b42Smillert 				operator = *p++;
12076fe57b42Smillert 
12086fe57b42Smillert 			endptr = p;
120996a888c6Smillert 			errno = 0;
121096a888c6Smillert 			d = strtod(p, &endptr);
121196a888c6Smillert 			if (errno == ERANGE)
12121e0ad43cSotto 				rval = ULLONG_MAX;	/* too big/small */
121396a888c6Smillert 			else if (*endptr != '\0') {
12146fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
12151e0ad43cSotto 				rval = ULLONG_MAX;
12166fe57b42Smillert 			} else {
121796a888c6Smillert 				/* XXX - should check for overflow */
121896a888c6Smillert 				if (mult > 0)
121914cc915fSmillert 					rval = d * mult * percent;
122096a888c6Smillert 				else
122196a888c6Smillert 					/* Negative mult means divide (fancy) */
122214cc915fSmillert 					rval = d / (-mult) * percent;
12236fe57b42Smillert 
122496a888c6Smillert 				/* Apply the operator */
12256fe57b42Smillert 				if (operator == '+')
12266fe57b42Smillert 					rval += oval;
12276fe57b42Smillert 				else if (operator == '-')
12286fe57b42Smillert 					rval = oval - rval;
12296fe57b42Smillert 			}
12306fe57b42Smillert 		}
12316fe57b42Smillert 	}
12328390cf28Smillert 	if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) {
123396a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
12348390cf28Smillert 		if (
1235fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
1236fc1a4cc6Sderaadt 		    ((lp->d_flags & D_VENDOR) || mult != 1) &&
1237fc1a4cc6Sderaadt #else
12388390cf28Smillert 		    mult != 1 &&
1239dbffb156Smillert #endif
12408390cf28Smillert 		    (rval + offset) % lp->d_secpercyl != 0) {
12411e0ad43cSotto 			u_int64_t cyls;
1242dbffb156Smillert 
12438390cf28Smillert 			/* Round to higher cylinder but no more than maxval */
12448390cf28Smillert 			cyls = (rval / lp->d_secpercyl) + 1;
12458390cf28Smillert 			if ((cyls * lp->d_secpercyl) - offset > maxval)
1246dbffb156Smillert 				cyls--;
12474b9a3bdaSmillert 			rval = (cyls * lp->d_secpercyl) - offset;
12488390cf28Smillert 			printf("Rounding to cylinder: %llu\n", rval);
12496fe57b42Smillert 		}
12504b9a3bdaSmillert 	}
12516fe57b42Smillert 
12526fe57b42Smillert 	return(rval);
12536fe57b42Smillert }
12546fe57b42Smillert 
12556fe57b42Smillert /*
12561f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
12571f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
12586fe57b42Smillert  */
12596fe57b42Smillert int
12601f0f871dSkrw has_overlap(struct disklabel *lp)
12616fe57b42Smillert {
12626fe57b42Smillert 	struct partition **spp;
1263e6aa8bafSmillert 	int c, i, j;
1264e6aa8bafSmillert 	char buf[BUFSIZ];
12656fe57b42Smillert 
12660fbd3c97Skrw 	/* Get a sorted list of the in-use partitions. */
12670fbd3c97Skrw 	spp = sort_partitions(lp);
12686fe57b42Smillert 
12690fbd3c97Skrw 	/* If there are less than two partitions in use, there is no overlap. */
12700fbd3c97Skrw 	if (spp[1] == NULL)
12710fbd3c97Skrw 		return(0);
12726fe57b42Smillert 
12736fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12740fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
12750fbd3c97Skrw 		for (j = i + 1; spp[j] != NULL; j++) {
12766fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
12771e0ad43cSotto 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) {
12786fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
12796fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
12806fe57b42Smillert 				    / sizeof(**spp);
12816fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
12826fe57b42Smillert 				    / sizeof(**spp);
12836fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
12846fe57b42Smillert 				    'a' + i, 'a' + j);
1285366bf641Skrw 				printf("#    %16.16s %16.16s  fstype "
1286651d5bd9Sotto 				    "[fsize bsize  cpg]\n", "size", "offset");
128734ae4198Skrw 				display_partition(stdout, lp, i, 0);
128834ae4198Skrw 				display_partition(stdout, lp, j, 0);
12896fe57b42Smillert 
1290e6aa8bafSmillert 				/* Get partition to disable or ^D */
1291e6aa8bafSmillert 				do {
1292616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
12936fe57b42Smillert 					    'a' + i, 'a' + j);
1294e6aa8bafSmillert 					buf[0] = '\0';
1295616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1296616cd1c4Smillert 						putchar('\n');
1297e6aa8bafSmillert 						return(1);	/* ^D */
1298616cd1c4Smillert 					}
1299e6aa8bafSmillert 					c = buf[0] - 'a';
1300e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1301e6aa8bafSmillert 				    c != i && c != j);
1302e6aa8bafSmillert 
1303e6aa8bafSmillert 				/* Mark the selected one as unused */
13046fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
13051f0f871dSkrw 				return (has_overlap(lp));
13066fe57b42Smillert 			}
13076fe57b42Smillert 		}
13086fe57b42Smillert 	}
1309f0b4d0a9Smillert 
1310e6aa8bafSmillert 	return(0);
13116fe57b42Smillert }
13126fe57b42Smillert 
13136fe57b42Smillert void
13149fdcb4d6Skrw edit_parms(struct disklabel *lp)
13156fe57b42Smillert {
13166fe57b42Smillert 	char *p;
13179fdcb4d6Skrw 	u_int64_t freesectors, ui;
131896a888c6Smillert 	struct disklabel oldlabel = *lp;
13196fe57b42Smillert 
1320ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
13216fe57b42Smillert 
13220f820bbbSmillert 	/* disk type */
13230f820bbbSmillert 	for (;;) {
1324c33fcabaSmillert 		p = getstring("disk type",
132541282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
132641282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
132796a888c6Smillert 		if (p == NULL) {
132896a888c6Smillert 			fputs("Command aborted\n", stderr);
132996a888c6Smillert 			return;
133096a888c6Smillert 		}
133141282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
133241282a2aSmillert 			ui = DTYPE_ESDI;
133341282a2aSmillert 		else
133441282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
133541282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13360f820bbbSmillert 				;
13370f820bbbSmillert 		if (ui < DKMAXTYPES) {
13380f820bbbSmillert 			break;
13390f820bbbSmillert 		} else {
13400f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13410f820bbbSmillert 			fputs("Valid types are: ", stdout);
13420f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13430f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13440f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13450f820bbbSmillert 					fputs(", ", stdout);
13460f820bbbSmillert 			}
13470f820bbbSmillert 			putchar('\n');
13480f820bbbSmillert 		}
13490f820bbbSmillert 	}
13500f820bbbSmillert 	lp->d_type = ui;
13510f820bbbSmillert 
13526fe57b42Smillert 	/* pack/label id */
1353c33fcabaSmillert 	p = getstring("label name",
13546fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13556fe57b42Smillert 	    lp->d_packname);
135696a888c6Smillert 	if (p == NULL) {
135796a888c6Smillert 		fputs("Command aborted\n", stderr);
135896a888c6Smillert 		*lp = oldlabel;		/* undo damage */
135996a888c6Smillert 		return;
136096a888c6Smillert 	}
13614fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
13626fe57b42Smillert 
13636fe57b42Smillert 	/* sectors/track */
13646fe57b42Smillert 	for (;;) {
1365dea75673Skrw 		ui = getuint(lp, "sectors/track",
1366cfd24250Skrw 		    "The Number of sectors per track.", lp->d_nsectors,
13674b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
13681e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
136996a888c6Smillert 			fputs("Command aborted\n", stderr);
137096a888c6Smillert 			*lp = oldlabel;		/* undo damage */
137196a888c6Smillert 			return;
13721e0ad43cSotto 		} if (ui == ULLONG_MAX)
13736fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13746fe57b42Smillert 		else
13756fe57b42Smillert 			break;
13766fe57b42Smillert 	}
13776fe57b42Smillert 	lp->d_nsectors = ui;
13786fe57b42Smillert 
13796fe57b42Smillert 	/* tracks/cylinder */
13806fe57b42Smillert 	for (;;) {
1381dea75673Skrw 		ui = getuint(lp, "tracks/cylinder",
13826fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
13834b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
13841e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
138596a888c6Smillert 			fputs("Command aborted\n", stderr);
138696a888c6Smillert 			*lp = oldlabel;		/* undo damage */
138796a888c6Smillert 			return;
13881e0ad43cSotto 		} else if (ui == ULLONG_MAX)
13896fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13906fe57b42Smillert 		else
13916fe57b42Smillert 			break;
13926fe57b42Smillert 	}
13936fe57b42Smillert 	lp->d_ntracks = ui;
13946fe57b42Smillert 
13956fe57b42Smillert 	/* sectors/cylinder */
1396148b6188Smillert 	for (;;) {
1397dea75673Skrw 		ui = getuint(lp, "sectors/cylinder",
1398148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
13994b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
14004b9a3bdaSmillert 		    0, 0);
14011e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
140296a888c6Smillert 			fputs("Command aborted\n", stderr);
140396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
140496a888c6Smillert 			return;
14051e0ad43cSotto 		} else if (ui == ULLONG_MAX)
1406148b6188Smillert 			fputs("Invalid entry\n", stderr);
1407148b6188Smillert 		else
1408148b6188Smillert 			break;
1409148b6188Smillert 	}
1410148b6188Smillert 	lp->d_secpercyl = ui;
14116fe57b42Smillert 
14126fe57b42Smillert 	/* number of cylinders */
14136fe57b42Smillert 	for (;;) {
1414dea75673Skrw 		ui = getuint(lp, "number of cylinders",
14156fe57b42Smillert 		    "The total number of cylinders on the disk.",
14164b9a3bdaSmillert 		    lp->d_ncylinders, lp->d_ncylinders, 0, 0);
14171e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
141896a888c6Smillert 			fputs("Command aborted\n", stderr);
141996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
142096a888c6Smillert 			return;
14211e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14226fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14236fe57b42Smillert 		else
14246fe57b42Smillert 			break;
14256fe57b42Smillert 	}
14266fe57b42Smillert 	lp->d_ncylinders = ui;
14276fe57b42Smillert 
14286fe57b42Smillert 	/* total sectors */
14296fe57b42Smillert 	for (;;) {
143034af67a3Sotto 		u_int64_t nsec = MAX(DL_GETDSIZE(lp),
143134af67a3Sotto 		    (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
1432dea75673Skrw 		ui = getuint(lp, "total sectors",
14336fe57b42Smillert 		    "The total number of sectors on the disk.",
1434baaa8969Smillert 		    nsec, nsec, 0, 0);
14351e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
143696a888c6Smillert 			fputs("Command aborted\n", stderr);
143796a888c6Smillert 			*lp = oldlabel;		/* undo damage */
143896a888c6Smillert 			return;
14391e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14406fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14411e0ad43cSotto 		else if (ui > DL_GETDSIZE(lp) &&
14421e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
1443f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1444f98aebd4Smillert 			    "partition.");
14456fe57b42Smillert 			break;
14461e0ad43cSotto 		} else if (ui < DL_GETDSIZE(lp) &&
14471e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
14486fe57b42Smillert 			/* shrink free count */
14499fdcb4d6Skrw 			freesectors = editor_countfree(lp);
14509fdcb4d6Skrw 			if (DL_GETDSIZE(lp) - ui > freesectors)
14516fe57b42Smillert 				fprintf(stderr,
14521e0ad43cSotto 				    "Not enough free space to shrink by %llu "
14531e0ad43cSotto 				    "sectors (only %llu sectors left)\n",
14549fdcb4d6Skrw 				    DL_GETDSIZE(lp) - ui, freesectors);
1455c4f83f03Skrw 			else
14566fe57b42Smillert 				break;
14576fe57b42Smillert 		} else
14586fe57b42Smillert 			break;
14596fe57b42Smillert 	}
146041ed49b7Smillert 	/* Adjust ending_sector if necessary. */
146196a888c6Smillert 	if (ending_sector > ui)
146296a888c6Smillert 		ending_sector = ui;
14631e0ad43cSotto 	DL_SETDSIZE(lp, ui);
14646fe57b42Smillert }
1465a7e61405Smillert 
1466a7e61405Smillert struct partition **
14670fbd3c97Skrw sort_partitions(struct disklabel *lp)
1468a7e61405Smillert {
1469d18c2a43Skrw 	static struct partition *spp[MAXPARTITIONS+2];
14700fbd3c97Skrw 	int i, npartitions;
1471a7e61405Smillert 
1472d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1473d18c2a43Skrw 
1474a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1475a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1476a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
14771e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1478a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1479a7e61405Smillert 	}
1480a7e61405Smillert 
1481a7e61405Smillert 	/*
1482a7e61405Smillert 	 * Sort the partitions based on starting offset.
1483a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1484a7e61405Smillert 	 */
1485a7e61405Smillert 	if (npartitions > 1)
1486a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1487a7e61405Smillert 		    partition_cmp))
1488a7e61405Smillert 			err(4, "failed to sort partition table");
1489a7e61405Smillert 
1490a7e61405Smillert 	return(spp);
1491a7e61405Smillert }
14920f820bbbSmillert 
14930f820bbbSmillert /*
14940f820bbbSmillert  * Get a valid disk type if necessary.
14950f820bbbSmillert  */
14960f820bbbSmillert void
14978809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev)
14980f820bbbSmillert {
14990f820bbbSmillert 	int i;
1500803ff7d5Smillert 	char *s, *def = "SCSI";
1501803ff7d5Smillert 	struct dtypes {
1502803ff7d5Smillert 		char *dev;
1503803ff7d5Smillert 		char *type;
1504803ff7d5Smillert 	} dtypes[] = {
1505c33fcabaSmillert 		{ "sd",   "SCSI" },
1506c33fcabaSmillert 		{ "rz",   "SCSI" },
1507c33fcabaSmillert 		{ "wd",   "IDE" },
1508c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1509c33fcabaSmillert 		{ "xd",   "SMD" },
1510c33fcabaSmillert 		{ "xy",   "SMD" },
1511c33fcabaSmillert 		{ "hd",   "HP-IB" },
1512c33fcabaSmillert 		{ "ccd",  "CCD" },
1513c33fcabaSmillert 		{ "vnd",  "VND" },
1514c33fcabaSmillert 		{ "svnd", "VND" },
1515c33fcabaSmillert 		{ NULL,   NULL }
1516803ff7d5Smillert 	};
1517803ff7d5Smillert 
1518803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1519803ff7d5Smillert 		if (*s == 'r')
1520803ff7d5Smillert 			s++;
1521803ff7d5Smillert 		i = strcspn(s, "0123456789");
1522803ff7d5Smillert 		s[i] = '\0';
1523803ff7d5Smillert 		dev = s;
1524803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1525803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1526803ff7d5Smillert 				def = dtypes[i].type;
1527803ff7d5Smillert 				break;
1528803ff7d5Smillert 			}
1529803ff7d5Smillert 		}
1530803ff7d5Smillert 	}
15310f820bbbSmillert 
15320f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15330f820bbbSmillert 		puts(banner);
15340f820bbbSmillert 		puts("Possible values are:");
1535eb5dd924Sderaadt 		printf("\"IDE\", ");
15360f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15370f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15380f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15390f820bbbSmillert 				fputs(", ", stdout);
15400f820bbbSmillert 		}
15410f820bbbSmillert 		putchar('\n');
15420f820bbbSmillert 
15430f820bbbSmillert 		for (;;) {
1544c33fcabaSmillert 			s = getstring("Disk type",
1545803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1546803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
154796a888c6Smillert 			if (s == NULL)
154896a888c6Smillert 				continue;
15495b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15505b412421Smillert 				lp->d_type = DTYPE_ESDI;
15515b412421Smillert 				return;
15525b412421Smillert 			}
15530f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15540f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15550f820bbbSmillert 					lp->d_type = i;
15560f820bbbSmillert 					return;
15570f820bbbSmillert 				}
15580f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15590f820bbbSmillert 			fputs("Valid types are: ", stdout);
15600f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15610f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15620f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15630f820bbbSmillert 					fputs(", ", stdout);
15640f820bbbSmillert 			}
15650f820bbbSmillert 			putchar('\n');
15660f820bbbSmillert 		}
15670f820bbbSmillert 	}
15680f820bbbSmillert }
156996a888c6Smillert 
157096a888c6Smillert /*
157196a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
157296a888c6Smillert  * from the user.
157396a888c6Smillert  */
157496a888c6Smillert void
15759fdcb4d6Skrw set_bounds(struct disklabel *lp)
157696a888c6Smillert {
15771e0ad43cSotto 	u_int64_t ui, start_temp;
157896a888c6Smillert 
157996a888c6Smillert 	/* Starting sector */
158096a888c6Smillert 	do {
1581dea75673Skrw 		ui = getuint(lp, "Starting sector",
158296a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
15831e0ad43cSotto 		  starting_sector, DL_GETDSIZE(lp), 0, 0);
15841e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
158596a888c6Smillert 			fputs("Command aborted\n", stderr);
158696a888c6Smillert 			return;
158796a888c6Smillert 		}
15881e0ad43cSotto 	} while (ui >= DL_GETDSIZE(lp));
158996a888c6Smillert 	start_temp = ui;
159096a888c6Smillert 
15914793b14cSmillert 	/* Size */
159296a888c6Smillert 	do {
1593dea75673Skrw 		ui = getuint(lp, "Size ('*' for entire disk)",
1594f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1595f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
15961e0ad43cSotto 		  DL_GETDSIZE(lp) - start_temp, 0, 0);
15971e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
159896a888c6Smillert 			fputs("Command aborted\n", stderr);
159996a888c6Smillert 			return;
160096a888c6Smillert 		}
16011e0ad43cSotto 	} while (ui > DL_GETDSIZE(lp) - start_temp);
16024793b14cSmillert 	ending_sector = start_temp + ui;
160396a888c6Smillert 	starting_sector = start_temp;
160496a888c6Smillert }
160596a888c6Smillert 
160696a888c6Smillert /*
16070d63cfbaSjsing  * Allow user to interactively change disklabel UID.
16080d63cfbaSjsing  */
16090d63cfbaSjsing void
16100d63cfbaSjsing set_uid(struct disklabel *lp)
16110d63cfbaSjsing {
16120d63cfbaSjsing 	u_int uid[8];
16130d63cfbaSjsing 	char *s;
16140d63cfbaSjsing 	int i;
16150d63cfbaSjsing 
16160d63cfbaSjsing 	printf("The disklabel UID is currently: ");
16170d63cfbaSjsing 	uid_print(stdout, lp);
16180d63cfbaSjsing 	printf("\n");
16190d63cfbaSjsing 
16200d63cfbaSjsing 	do {
16210d63cfbaSjsing 		s = getstring("uid", "The disklabel UID, given as a 16 "
16220d63cfbaSjsing 		    "character hexadecimal string.", NULL);
1623ce98d1aeShalex 		if (s == NULL || strlen(s) == 0) {
16240d63cfbaSjsing 			fputs("Command aborted\n", stderr);
16250d63cfbaSjsing 			return;
16260d63cfbaSjsing 		}
16270d63cfbaSjsing 		i = uid_parse(lp, s);
16280d63cfbaSjsing 		if (i != 0)
16290d63cfbaSjsing 			fputs("Invalid UID entered.\n", stderr);
16300d63cfbaSjsing 	} while (i != 0);
16310d63cfbaSjsing }
16320d63cfbaSjsing 
16330d63cfbaSjsing /*
163496a888c6Smillert  * Return a list of the "chunks" of free space available
163596a888c6Smillert  */
163696a888c6Smillert struct diskchunk *
16378809fabbSderaadt free_chunks(struct disklabel *lp)
163896a888c6Smillert {
163996a888c6Smillert 	struct partition **spp;
164096a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
164199bd27d2Skrw 	u_int64_t start, stop;
164296a888c6Smillert 	int i, numchunks;
164396a888c6Smillert 
16440fbd3c97Skrw 	/* Sort the in-use partitions based on offset */
16450fbd3c97Skrw 	spp = sort_partitions(lp);
164696a888c6Smillert 
164796a888c6Smillert 	/* If there are no partitions, it's all free. */
16480fbd3c97Skrw 	if (spp[0] == NULL) {
16492d8451b0Smillert 		chunks[0].start = starting_sector;
165096a888c6Smillert 		chunks[0].stop = ending_sector;
165196a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
165296a888c6Smillert 		return(chunks);
165396a888c6Smillert 	}
165496a888c6Smillert 
165596a888c6Smillert 	/* Find chunks of free space */
165696a888c6Smillert 	numchunks = 0;
16570fbd3c97Skrw 	if (DL_GETPOFFSET(spp[0]) > starting_sector) {
16582d8451b0Smillert 		chunks[0].start = starting_sector;
16591e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
166096a888c6Smillert 		numchunks++;
166196a888c6Smillert 	}
16620fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
166399bd27d2Skrw 		start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1664aff3f969Sotto 		if (start < starting_sector)
1665aff3f969Sotto 			start = starting_sector;
1666aff3f969Sotto 		else if (start > ending_sector)
1667aff3f969Sotto 			start = ending_sector;
166899bd27d2Skrw 		if (spp[i + 1] != NULL)
166999bd27d2Skrw 			stop = DL_GETPOFFSET(spp[i+1]);
167099bd27d2Skrw 		else
167199bd27d2Skrw 			stop = ending_sector;
1672aff3f969Sotto 		if (stop < starting_sector)
1673aff3f969Sotto 			stop = starting_sector;
1674aff3f969Sotto 		else if (stop > ending_sector)
1675aff3f969Sotto 			stop = ending_sector;
167699bd27d2Skrw 		if (start < stop) {
167799bd27d2Skrw 			chunks[numchunks].start = start;
167899bd27d2Skrw 			chunks[numchunks].stop = stop;
167996a888c6Smillert 			numchunks++;
168096a888c6Smillert 		}
168196a888c6Smillert 	}
168296a888c6Smillert 
168396a888c6Smillert 	/* Terminate and return */
168496a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
168596a888c6Smillert 	return(chunks);
168696a888c6Smillert }
16874793b14cSmillert 
16884793b14cSmillert void
168987023ed9Skrw find_bounds(struct disklabel *lp)
16904793b14cSmillert {
16916534e983Sderaadt 	starting_sector = DL_GETBSTART(lp);
16926534e983Sderaadt 	ending_sector = DL_GETBEND(lp);
1693b2d4a455Smiod 
16946534e983Sderaadt 	if (ending_sector) {
169534ae4198Skrw 		if (verbose)
169634ae4198Skrw 			printf("Treating sectors %llu-%llu as the OpenBSD"
169734ae4198Skrw 			    " portion of the disk.\nYou can use the 'b'"
169834ae4198Skrw 			    " command to change this.\n\n", starting_sector,
169934ae4198Skrw 			    ending_sector);
1700b2d4a455Smiod 	} else {
1701b2d4a455Smiod #if (NUMBOOT == 1)
1702d3f02056Smillert 		/* Boot blocks take up the first cylinder */
1703d3f02056Smillert 		starting_sector = lp->d_secpercyl;
170434ae4198Skrw 		if (verbose)
170534ae4198Skrw 			printf("Reserving the first data cylinder for boot"
170634ae4198Skrw 			    " blocks.\nYou can use the 'b' command to change"
170734ae4198Skrw 			    " this.\n\n");
17084793b14cSmillert #endif
17094793b14cSmillert 	}
1710b2d4a455Smiod }
1711c0bdc608Smillert 
1712c0bdc608Smillert /*
1713c0bdc608Smillert  * Calculate free space.
1714c0bdc608Smillert  */
17159fdcb4d6Skrw u_int64_t
17169fdcb4d6Skrw editor_countfree(struct disklabel *lp)
1717c0bdc608Smillert {
1718d93cb2bbSkrw 	struct diskchunk *chunks;
17199fdcb4d6Skrw 	u_int64_t freesectors = 0;
1720c0bdc608Smillert 	int i;
1721c0bdc608Smillert 
1722d93cb2bbSkrw 	chunks = free_chunks(lp);
1723509930fbSotto 
1724d93cb2bbSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++)
17259fdcb4d6Skrw 		freesectors += chunks[i].stop - chunks[i].start;
17269fdcb4d6Skrw 
17279fdcb4d6Skrw 	return (freesectors);
1728c0bdc608Smillert }
1729617e6e4aSmillert 
1730617e6e4aSmillert void
17314d812bb6Slum editor_help(void)
1732617e6e4aSmillert {
1733617e6e4aSmillert 	puts("Available commands:");
1734617e6e4aSmillert 	puts(
17354d812bb6Slum "  ? | h    - show help                  n [part] - set mount point\n"
173649159a67Skrw "  A        - auto partition all space   p [unit] - print partitions\n"
173749159a67Skrw "  a [part] - add partition              q        - quit & save changes\n"
17386aaa4aabSotto "  b        - set OpenBSD boundaries     R [part] - resize a partition\n"
173949159a67Skrw "  c [part] - change partition size      r        - display free space\n"
17406aaa4aabSotto "  D        - reset label to default     s [path] - save label to file\n"
17416aaa4aabSotto "  d [part] - delete partition           U        - undo all changes\n"
17426aaa4aabSotto "  e        - edit drive parameters      u        - undo last change\n"
17436aaa4aabSotto "  g [d|u]  - [d]isk or [u]ser geometry  w        - write label to disk\n"
17440d63cfbaSjsing "  i        - modify disklabel UID       X        - toggle expert mode\n"
17450d63cfbaSjsing "  l [unit] - print disk label header    x        - exit & lose changes\n"
17460d63cfbaSjsing "  M        - disklabel(8) man page      z        - delete all partitions\n"
17470d63cfbaSjsing "  m [part] - modify partition\n"
1748c4884206Skrw "\n"
1749c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1750c4884206Skrw "\t'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes)\n"
1751c4884206Skrw "\t'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1752c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
17534d812bb6Slum 
1754617e6e4aSmillert }
1755bd6726faSmillert 
17564f3bbbf0Skrw void
17578809fabbSderaadt mpcopy(char **to, char **from)
1758bd6726faSmillert {
1759bd6726faSmillert 	int i;
17600612d09dSderaadt 	char *top;
1761bd6726faSmillert 
1762bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1763bd6726faSmillert 		if (from[i] != NULL) {
1764dcab0d16Sderaadt 			int len = strlen(from[i]) + 1;
1765dcab0d16Sderaadt 
17660612d09dSderaadt 			top = realloc(to[i], len);
17670612d09dSderaadt 			if (top == NULL)
1768bd6726faSmillert 				errx(4, "out of memory");
17690612d09dSderaadt 			to[i] = top;
1770dcab0d16Sderaadt 			(void)strlcpy(to[i], from[i], len);
1771bd6726faSmillert 		} else if (to[i] != NULL) {
1772bd6726faSmillert 			free(to[i]);
1773bd6726faSmillert 			to[i] = NULL;
1774bd6726faSmillert 		}
1775bd6726faSmillert 	}
1776bd6726faSmillert }
1777bd6726faSmillert 
1778bd6726faSmillert int
17798809fabbSderaadt mpequal(char **mp1, char **mp2)
1780bd6726faSmillert {
1781bd6726faSmillert 	int i;
1782bd6726faSmillert 
1783bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1784bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1785bd6726faSmillert 			continue;
1786bd6726faSmillert 
1787bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1788bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1789bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1790bd6726faSmillert 			return(0);
1791bd6726faSmillert 	}
1792bd6726faSmillert 	return(1);
1793bd6726faSmillert }
1794bd6726faSmillert 
179593160b9bSkrw void
179634ae4198Skrw mpsave(struct disklabel *lp)
1797bd6726faSmillert {
1798d8b446ceSderaadt 	int i, j;
1799bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
18003f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1801bd6726faSmillert 	FILE *fp;
1802bd6726faSmillert 
180393160b9bSkrw 	if (!fstabfile)
180493160b9bSkrw 		return;
180593160b9bSkrw 
18063f843443Smillert 	memset(&mi, 0, sizeof(mi));
18073f843443Smillert 
1808d8b446ceSderaadt 	for (i = 0; i < MAXPARTITIONS; i++) {
180934ae4198Skrw 		if (mountpoints[i] != NULL) {
181034ae4198Skrw 			mi[i].mountpoint = mountpoints[i];
18113f843443Smillert 			mi[i].partno = i;
1812bd6726faSmillert 		}
1813bd6726faSmillert 	}
1814bd6726faSmillert 
181534ae4198Skrw 	/* Convert specname to bdev */
181634ae4198Skrw 	if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
181734ae4198Skrw 	    specname[sizeof(_PATH_DEV) - 1] == 'r') {
1818bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
181934ae4198Skrw 		    &specname[sizeof(_PATH_DEV)]);
1820bd6726faSmillert 	} else {
182134ae4198Skrw 		if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
182293160b9bSkrw 			return;
1823bd6726faSmillert 		*p = '\0';
182434ae4198Skrw 		snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1825bd6726faSmillert 		*p = 'r';
1826bd6726faSmillert 	}
1827bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1828bd6726faSmillert 
18293f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
18303f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
18313f843443Smillert 
183293160b9bSkrw 	if (fp = fopen(fstabfile, "w")) {
183393160b9bSkrw 		for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint; i++) {
18345fea0b85Smillert 			j =  mi[i].partno;
18355fea0b85Smillert 			fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j,
18363f843443Smillert 			    mi[i].mountpoint,
18375fea0b85Smillert 			    fstypesnames[lp->d_partitions[j].p_fstype],
18385fea0b85Smillert 			    j == 0 ? 1 : 2);
1839bd6726faSmillert 		}
1840bd6726faSmillert 		fclose(fp);
184193160b9bSkrw 	}
1842bd6726faSmillert }
184324a2c1a4Smillert 
184424a2c1a4Smillert int
1845604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
184624a2c1a4Smillert {
1847604d3bdeSkrw 	struct diskchunk *chunks;
184824a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
184915c15d8aSkrw 	u_int64_t ui, maxsize;
1850604d3bdeSkrw 	int i, fstype;
185124a2c1a4Smillert 
1852dea75673Skrw 	ui = getuint(lp, "offset",
18531e0ad43cSotto 	   "Starting sector for this partition.",
18541e0ad43cSotto 	   DL_GETPOFFSET(pp),
18551e0ad43cSotto 	   DL_GETPOFFSET(pp), 0, DO_CONVERSIONS |
185624a2c1a4Smillert 	   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
1857e9ff19beSkrw 
1858e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
185924a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1860e9ff19beSkrw 	else if (ui == ULLONG_MAX)
186124a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
186240e98e9fSkrw 	else if (ui < starting_sector || ui >= ending_sector)
1863e9ff19beSkrw 		fprintf(stderr, "The offset must be >= %llu and < %llu, "
1864e9ff19beSkrw 		    "the limits of the OpenBSD portion\n"
1865e9ff19beSkrw 		    "of the disk. The 'b' command can change these limits.\n",
186640e98e9fSkrw 		    starting_sector, ending_sector);
1867fc1a4cc6Sderaadt #ifdef SUN_AAT0
186849bf537cSderaadt 	else if (partno == 0 && ui != 0)
186949bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
187040f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
187149bf537cSderaadt #endif
187215c15d8aSkrw 	else {
1873604d3bdeSkrw 		fstype = pp->p_fstype;
1874604d3bdeSkrw 		pp->p_fstype = FS_UNUSED;
1875604d3bdeSkrw 		chunks = free_chunks(lp);
1876604d3bdeSkrw 		pp->p_fstype = fstype;
1877e9ff19beSkrw 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
1878e9ff19beSkrw 			if (ui < chunks[i].start || ui >= chunks[i].stop)
187915c15d8aSkrw 				continue;
18801e0ad43cSotto 			DL_SETPOFFSET(pp, ui);
188115c15d8aSkrw 			maxsize = chunks[i].stop - DL_GETPOFFSET(pp);
188215c15d8aSkrw 			if (DL_GETPSIZE(pp) > maxsize)
188315c15d8aSkrw 				DL_SETPSIZE(pp, maxsize);
188424a2c1a4Smillert 			return (0);
188524a2c1a4Smillert 		}
188615c15d8aSkrw 		fputs("The offset must be in a free area.\n", stderr);
188715c15d8aSkrw 	}
1888e9ff19beSkrw 
1889e9ff19beSkrw 	/* Partition offset was not set. */
1890e9ff19beSkrw 	return (1);
189115c15d8aSkrw }
189224a2c1a4Smillert 
189324a2c1a4Smillert int
18949fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
189524a2c1a4Smillert {
189624a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
189714192793Skrw 	u_int64_t maxsize, ui;
189814192793Skrw 
189914192793Skrw 	maxsize = max_partition_size(lp, partno);
190024a2c1a4Smillert 
1901dea75673Skrw 	ui = getuint(lp, "size", "Size of the partition. "
19027da73705Skrw 	    "You may also say +/- amount for a relative change.",
190314192793Skrw 	    DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp),
1904525051f1Sotto 	    DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS ||
1905525051f1Sotto 	    pp->p_fstype == FS_SWAP) ?  DO_ROUNDING : 0));
1906e9ff19beSkrw 
1907e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
190824a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1909e9ff19beSkrw 	else if (ui == ULLONG_MAX)
191024a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
191128e3704eSkrw 	else if (ui == 0)
191228e3704eSkrw 		fputs("The size must be > 0\n", stderr);
191340e98e9fSkrw 	else if (ui + DL_GETPOFFSET(pp) > ending_sector)
191440e98e9fSkrw 		fprintf(stderr, "The size can't be more than "
191540e98e9fSkrw 		    "%llu sectors, or the partition would\n"
191640e98e9fSkrw 		    "extend beyond the last sector (%llu) of the "
191740e98e9fSkrw 		    "OpenBSD portion of\nthe disk. "
191840e98e9fSkrw 		    "The 'b' command can change this limit.\n",
191940e98e9fSkrw 		    ending_sector - DL_GETPOFFSET(pp), ending_sector);
192014192793Skrw 	else if (ui > maxsize)
192114192793Skrw 		fprintf(stderr,"Sorry, there are only %llu sectors left\n",
192214192793Skrw 		    maxsize);
192359ccf790Skrw 	else {
192459ccf790Skrw 		DL_SETPSIZE(pp, ui);
192524a2c1a4Smillert 		return (0);
192624a2c1a4Smillert 	}
1927e9ff19beSkrw 
1928e9ff19beSkrw 	/* Partition size was not set. */
1929e9ff19beSkrw 	return (1);
1930e9ff19beSkrw }
193124a2c1a4Smillert 
193224a2c1a4Smillert int
19338809fabbSderaadt get_fsize(struct disklabel *lp, int partno)
193424a2c1a4Smillert {
19351e0ad43cSotto 	u_int64_t ui, fsize, frag;
193624a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
193724a2c1a4Smillert 
1938a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
1939a4c87e64Skrw 		return (0);
1940a4c87e64Skrw 
1941ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1942ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1943ddfcbf38Sotto 	if (fsize == 0)
1944ddfcbf38Sotto 		frag = 8;
1945ddfcbf38Sotto 
194624a2c1a4Smillert 	for (;;) {
1947dea75673Skrw 		ui = getuint(lp, "fragment size",
19483c92d7f2Stedu 		    "Size of fs block fragments.  Usually 2048 or 512.",
1949ddfcbf38Sotto 		    fsize, fsize, 0, 0);
19501e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
195124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
195224a2c1a4Smillert 			return(1);
19531e0ad43cSotto 		} else if (ui == ULLONG_MAX)
195424a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
195524a2c1a4Smillert 		else
195624a2c1a4Smillert 			break;
195724a2c1a4Smillert 	}
195824a2c1a4Smillert 	if (ui == 0)
195924a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
1960ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag);
196124a2c1a4Smillert 	return(0);
196224a2c1a4Smillert }
196324a2c1a4Smillert 
196424a2c1a4Smillert int
19658809fabbSderaadt get_bsize(struct disklabel *lp, int partno)
196624a2c1a4Smillert {
1967*a49bdda8Skrw 	u_int64_t adj, ui, bsize, frag, fsize;
196824a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
196924a2c1a4Smillert 
1970*a49bdda8Skrw 	if (pp->p_fstype != FS_BSDFFS)
1971a4c87e64Skrw 		return (0);
1972a4c87e64Skrw 
197324a2c1a4Smillert 	/* Avoid dividing by zero... */
1974ddfcbf38Sotto 	if (pp->p_fragblock == 0)
197524a2c1a4Smillert 		return(1);
1976ddfcbf38Sotto 
1977*a49bdda8Skrw 	if (!expert)
1978*a49bdda8Skrw 		goto align;
1979*a49bdda8Skrw 
1980ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1981ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
198224a2c1a4Smillert 
198324a2c1a4Smillert 	for (;;) {
1984dea75673Skrw 		ui = getuint(lp, "block size",
19853c92d7f2Stedu 		    "Size of filesystem blocks.  Usually 16384 or 4096.",
1986ddfcbf38Sotto 		    fsize * frag, fsize * frag,
198724a2c1a4Smillert 		    0, 0);
198824a2c1a4Smillert 
198924a2c1a4Smillert 		/* sanity checks */
19901e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
199124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
199224a2c1a4Smillert 			return(1);
19931e0ad43cSotto 		} else if (ui == ULLONG_MAX)
199424a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
199524a2c1a4Smillert 		else if (ui < getpagesize())
199624a2c1a4Smillert 			fprintf(stderr,
199724a2c1a4Smillert 			    "Error: block size must be at least as big "
199824a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
1999ddfcbf38Sotto 		else if (ui % fsize != 0)
200024a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
200124a2c1a4Smillert 			    "fragment size.\n", stderr);
2002ddfcbf38Sotto 		else if (ui / fsize < 1)
200324a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
200424a2c1a4Smillert 			    "fragment size.\n", stderr);
200524a2c1a4Smillert 		else
200624a2c1a4Smillert 			break;
200724a2c1a4Smillert 	}
2008ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag);
2009*a49bdda8Skrw 
2010*a49bdda8Skrw align:
2011*a49bdda8Skrw #ifndef SUN_CYLCHECK
2012*a49bdda8Skrw 	bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) *
2013*a49bdda8Skrw 	    DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize;
2014*a49bdda8Skrw 	if (DL_GETPOFFSET(pp) != starting_sector) {
2015*a49bdda8Skrw 		/* Can't change offset of first partition. */
2016*a49bdda8Skrw 		adj = bsize - (DL_GETPOFFSET(pp) % bsize);
2017*a49bdda8Skrw 		if (adj != 0 && adj != bsize) {
2018*a49bdda8Skrw 			DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj);
2019*a49bdda8Skrw 			DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj);
2020*a49bdda8Skrw 		}
2021*a49bdda8Skrw 	}
2022*a49bdda8Skrw 	/* Always align end. */
2023*a49bdda8Skrw 	adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize;
2024*a49bdda8Skrw 	if (adj > 0)
2025*a49bdda8Skrw 		DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj);
2026*a49bdda8Skrw #endif
202724a2c1a4Smillert 	return(0);
202824a2c1a4Smillert }
202924a2c1a4Smillert 
203024a2c1a4Smillert int
20318809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
203224a2c1a4Smillert {
203324a2c1a4Smillert 	char *p;
20341e0ad43cSotto 	u_int64_t ui;
203524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
203624a2c1a4Smillert 
203724a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
2038c33fcabaSmillert 		p = getstring("FS type",
203924a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
204024a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
204124a2c1a4Smillert 		if (p == NULL) {
204224a2c1a4Smillert 			fputs("Command aborted\n", stderr);
204324a2c1a4Smillert 			return(1);
204424a2c1a4Smillert 		}
204524a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
204624a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
204724a2c1a4Smillert 				pp->p_fstype = ui;
204824a2c1a4Smillert 				break;
204924a2c1a4Smillert 			}
205024a2c1a4Smillert 		}
205124a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
205224a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
205324a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
205424a2c1a4Smillert 		}
205524a2c1a4Smillert 	} else {
205624a2c1a4Smillert 		for (;;) {
2057dea75673Skrw 			ui = getuint(lp, "FS type (decimal)",
205824a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
205924a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
20601e0ad43cSotto 			if (ui == ULLONG_MAX - 1) {
206124a2c1a4Smillert 				fputs("Command aborted\n", stderr);
206224a2c1a4Smillert 				return(1);
20631e0ad43cSotto 			} if (ui == ULLONG_MAX)
206424a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
206524a2c1a4Smillert 			else
206624a2c1a4Smillert 				break;
206724a2c1a4Smillert 		}
206824a2c1a4Smillert 		pp->p_fstype = ui;
206924a2c1a4Smillert 	}
207024a2c1a4Smillert 	return(0);
207124a2c1a4Smillert }
207224a2c1a4Smillert 
207324a2c1a4Smillert int
207434ae4198Skrw get_mp(struct disklabel *lp, int partno)
207524a2c1a4Smillert {
207624a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
2077ec9fde5fSkrw 	char *p;
2078ec9fde5fSkrw 	int i;
207924a2c1a4Smillert 
208034ae4198Skrw 	if (fstabfile && pp->p_fstype != FS_UNUSED &&
208124a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
208224a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
2083ddaff619Smillert 		for (;;) {
2084c33fcabaSmillert 			p = getstring("mount point",
208524a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
208634ae4198Skrw 			    mountpoints[partno] ? mountpoints[partno] : "none");
208724a2c1a4Smillert 			if (p == NULL) {
208824a2c1a4Smillert 				fputs("Command aborted\n", stderr);
208924a2c1a4Smillert 				return(1);
209024a2c1a4Smillert 			}
2091ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
209234ae4198Skrw 				free(mountpoints[partno]);
209334ae4198Skrw 				mountpoints[partno] = NULL;
2094ddaff619Smillert 				break;
2095ddaff619Smillert 			}
2096ec9fde5fSkrw 			for (i = 0; i < MAXPARTITIONS; i++)
209793160b9bSkrw 				if (mountpoints[i] != NULL && i != partno &&
2098ec9fde5fSkrw 				    strcmp(p, mountpoints[i]) == 0)
2099ec9fde5fSkrw 					break;
2100ec9fde5fSkrw 			if (i < MAXPARTITIONS) {
210193160b9bSkrw 				fprintf(stderr, "'%c' already being mounted at "
210293160b9bSkrw 				    "'%s'\n", 'a'+i, p);
2103ec9fde5fSkrw 				break;
2104ec9fde5fSkrw 			}
2105ddaff619Smillert 			if (*p == '/') {
2106ddaff619Smillert 				/* XXX - might as well realloc */
210734ae4198Skrw 				free(mountpoints[partno]);
210834ae4198Skrw 				if ((mountpoints[partno] = strdup(p)) == NULL)
210924a2c1a4Smillert 					errx(4, "out of memory");
2110ddaff619Smillert 				break;
2111ddaff619Smillert 			}
2112ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
211324a2c1a4Smillert 		}
211424a2c1a4Smillert 	}
211524a2c1a4Smillert 	return(0);
211624a2c1a4Smillert }
21173f843443Smillert 
21183f843443Smillert int
21198809fabbSderaadt micmp(const void *a1, const void *a2)
21203f843443Smillert {
21213f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
21223f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
21233f843443Smillert 
21243f843443Smillert 	/* We want all the NULLs at the end... */
21253f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
21263f843443Smillert 		return(0);
21273f843443Smillert 	else if (mi1->mountpoint == NULL)
21283f843443Smillert 		return(1);
21293f843443Smillert 	else if (mi2->mountpoint == NULL)
21303f843443Smillert 		return(-1);
21313f843443Smillert 	else
21323f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
21333f843443Smillert }
2134c33fcabaSmillert 
2135c33fcabaSmillert void
213687023ed9Skrw get_geometry(int f, struct disklabel **dgpp)
2137c33fcabaSmillert {
2138c33fcabaSmillert 	struct stat st;
2139c33fcabaSmillert 	struct disklabel *disk_geop;
214087023ed9Skrw 
2141c33fcabaSmillert 	if (fstat(f, &st) == -1)
2142c33fcabaSmillert 		err(4, "Can't stat device");
2143c33fcabaSmillert 
2144c33fcabaSmillert 	/* Get disk geometry */
2145c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2146c33fcabaSmillert 		errx(4, "out of memory");
2147c33fcabaSmillert 	if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 &&
2148c33fcabaSmillert 	    ioctl(f, DIOCGDINFO, disk_geop) < 0)
2149c33fcabaSmillert 		err(4, "ioctl DIOCGDINFO");
2150c33fcabaSmillert 	*dgpp = disk_geop;
2151c33fcabaSmillert }
2152c33fcabaSmillert 
2153c33fcabaSmillert void
21548809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp,
215587023ed9Skrw     struct disklabel *ugp, char *p)
2156c33fcabaSmillert {
2157c33fcabaSmillert 	if (p == NULL) {
21589a36aa41Ssthen 		p = getstring("[d]isk or [u]ser geometry",
2159c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
21609a36aa41Ssthen 		    "itself thinks it is, or 'u' to use the geometry that "
21619a36aa41Ssthen 		    "was found in the label.",
2162c33fcabaSmillert 		    "d");
2163c33fcabaSmillert 	}
2164c33fcabaSmillert 	if (p == NULL) {
2165c33fcabaSmillert 		fputs("Command aborted\n", stderr);
2166c33fcabaSmillert 		return;
2167c33fcabaSmillert 	}
2168c33fcabaSmillert 	switch (*p) {
2169c33fcabaSmillert 	case 'd':
2170c33fcabaSmillert 	case 'D':
2171c33fcabaSmillert 		if (dgp == NULL)
2172c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2173c33fcabaSmillert 		else {
2174c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
2175c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
2176c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
2177c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
2178c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
217934af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(dgp));
2180c33fcabaSmillert 		}
2181c33fcabaSmillert 		break;
2182c33fcabaSmillert 	case 'u':
2183c33fcabaSmillert 	case 'U':
2184c33fcabaSmillert 		if (ugp == NULL)
2185c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2186c33fcabaSmillert 		else {
2187c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2188c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2189c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2190c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2191c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
219234af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(ugp));
2193c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2194c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2195c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2196c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2197c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
219834af67a3Sotto 			    DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp))
2199c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2200c33fcabaSmillert 				    "geometry.\n", stderr);
2201c33fcabaSmillert 		}
2202c33fcabaSmillert 		break;
2203c33fcabaSmillert 	default:
22049a36aa41Ssthen 		fputs("You must enter either 'd' or 'u'.\n", stderr);
2205c33fcabaSmillert 		break;
2206c33fcabaSmillert 	}
2207c33fcabaSmillert }
22089afbe9eeSmillert 
22099afbe9eeSmillert void
22109fdcb4d6Skrw zero_partitions(struct disklabel *lp)
22119afbe9eeSmillert {
22129afbe9eeSmillert 	int i;
22139afbe9eeSmillert 
2214b4ed6301Skrw 	for (i = 0; i < MAXPARTITIONS; i++) {
22159afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
2216b4ed6301Skrw 		free(mountpoints[i]);
2217b4ed6301Skrw 		mountpoints[i] = NULL;
2218b4ed6301Skrw 	}
2219b4ed6301Skrw 
222034af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
22219afbe9eeSmillert }
222214192793Skrw 
222314192793Skrw u_int64_t
222414192793Skrw max_partition_size(struct disklabel *lp, int partno)
222514192793Skrw {
222614192793Skrw 	struct partition *pp = &lp->d_partitions[partno];
222714192793Skrw 	struct diskchunk *chunks;
222844ffe03bSotto 	u_int64_t maxsize = 0, offset;
222914192793Skrw 	int fstype, i;
223014192793Skrw 
223114192793Skrw 	fstype = pp->p_fstype;
223214192793Skrw 	pp->p_fstype = FS_UNUSED;
223314192793Skrw 	chunks = free_chunks(lp);
223414192793Skrw 	pp->p_fstype = fstype;
223514192793Skrw 
223614192793Skrw 	offset = DL_GETPOFFSET(pp);
223714192793Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
223814192793Skrw 		if (offset < chunks[i].start || offset >= chunks[i].stop)
223914192793Skrw 			continue;
224014192793Skrw 		maxsize = chunks[i].stop - offset;
224114192793Skrw 		break;
224214192793Skrw 	}
224314192793Skrw 	return (maxsize);
224414192793Skrw }
2245aff3f969Sotto 
2246aff3f969Sotto void
2247aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp)
2248aff3f969Sotto {
2249aff3f969Sotto 	double d = scale(sz, unit, lp);
2250aff3f969Sotto 	if (d < 0)
2251aff3f969Sotto 		printf("%llu", sz);
2252aff3f969Sotto 	else
2253aff3f969Sotto 		printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
2254aff3f969Sotto }
2255aff3f969Sotto 
2256aff3f969Sotto void
225734ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr)
2258aff3f969Sotto {
2259aff3f969Sotto 	int i;
2260aff3f969Sotto 
2261352d199bSkrw 	unit = canonical_unit(lp, unit);
2262aff3f969Sotto 
2263aff3f969Sotto 	printf("OpenBSD area: ");
226459882f1dSkrw 	psize(starting_sector, 0, lp);
2265aff3f969Sotto 	printf("-");
226659882f1dSkrw 	psize(ending_sector, 0, lp);
2267aff3f969Sotto 	printf("; size: ");
2268aff3f969Sotto 	psize(ending_sector - starting_sector, unit, lp);
2269aff3f969Sotto 	printf("; free: ");
2270aff3f969Sotto 	psize(fr, unit, lp);
2271aff3f969Sotto 
2272aff3f969Sotto 	printf("\n#    %16.16s %16.16s  fstype [fsize bsize  cpg]\n",
2273aff3f969Sotto 	    "size", "offset");
2274aff3f969Sotto 	for (i = 0; i < lp->d_npartitions; i++)
227534ae4198Skrw 		display_partition(stdout, lp, i, unit);
2276aff3f969Sotto }
2277aff3f969Sotto 
2278