xref: /openbsd/sbin/disklabel/editor.c (revision 5f012d92)
1*5f012d92Snaddy /*	$OpenBSD: editor.c,v 1.366 2021/02/03 14:41:40 naddy Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
4bf198cc6Smillert  * Copyright (c) 1997-2000 Todd C. Miller <millert@openbsd.org>
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 
1978eb0b7eSderaadt #include <sys/param.h>	/* MAXBSIZE DEV_BSIZE */
206fe57b42Smillert #include <sys/types.h>
21b9fc9a72Sderaadt #include <sys/signal.h>
22c33fcabaSmillert #include <sys/stat.h>
23c33fcabaSmillert #include <sys/ioctl.h>
2491f4f7d8Sdlg #include <sys/dkio.h>
258dde8bb6Sotto #include <sys/sysctl.h>
266fe57b42Smillert #define	DKTYPENAMES
276fe57b42Smillert #include <sys/disklabel.h>
286fe57b42Smillert 
296fe57b42Smillert #include <ufs/ffs/fs.h>
306fe57b42Smillert 
316fe57b42Smillert #include <ctype.h>
326fe57b42Smillert #include <err.h>
336fe57b42Smillert #include <errno.h>
346fe57b42Smillert #include <string.h>
35803ff7d5Smillert #include <libgen.h>
36f1bc1b27Skrw #include <stdint.h>
376fe57b42Smillert #include <stdio.h>
386fe57b42Smillert #include <stdlib.h>
396fe57b42Smillert #include <unistd.h>
40b9fc9a72Sderaadt #include <limits.h>
416fe57b42Smillert 
42f21a098bSotto #include "extern.h"
434793b14cSmillert #include "pathnames.h"
444793b14cSmillert 
45b9fc9a72Sderaadt #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
46b9fc9a72Sderaadt 
47117239d3Skrw /* flags for getuint64() */
486fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
496fe57b42Smillert #define	DO_ROUNDING	0x00000002
506fe57b42Smillert 
5140b226e8Skrw /* flags for alignpartition() */
5240b226e8Skrw #define	ROUND_OFFSET_UP		0x00000001
5340b226e8Skrw #define	ROUND_OFFSET_DOWN	0x00000002
5440b226e8Skrw #define	ROUND_SIZE_UP		0x00000004
5540b226e8Skrw #define	ROUND_SIZE_DOWN		0x00000008
56922b28b8Skrw #define	ROUND_SIZE_OVERLAP	0x00000010
5740b226e8Skrw 
580db7769aSkrw /* Special return values for getnumber and getuint64() */
59aa3970cdSkrw #define	CMD_ABORTED	(ULLONG_MAX - 1)
60aa3970cdSkrw #define	CMD_BADVALUE	(ULLONG_MAX)
61aa3970cdSkrw 
6296a888c6Smillert /* structure to describe a portion of a disk */
6396a888c6Smillert struct diskchunk {
641e0ad43cSotto 	u_int64_t start;
651e0ad43cSotto 	u_int64_t stop;
6696a888c6Smillert };
6796a888c6Smillert 
683f843443Smillert /* used when sorting mountpoints in mpsave() */
693f843443Smillert struct mountinfo {
703f843443Smillert 	char *mountpoint;
713f843443Smillert 	int partno;
723f843443Smillert };
733f843443Smillert 
74557f712bSkrw /* used when allocating all space according to recommendations */
75557f712bSkrw 
76557f712bSkrw struct space_allocation {
77eafadddfSkrw 	u_int64_t	minsz;	/* starts as blocks, xlated to sectors. */
78eafadddfSkrw 	u_int64_t	maxsz;	/* starts as blocks, xlated to sectors. */
79557f712bSkrw 	int		rate;	/* % of extra space to use */
80557f712bSkrw 	char	       *mp;
81557f712bSkrw };
82557f712bSkrw 
83e485502dSkrw /*
84e485502dSkrw  * NOTE! Changing partition sizes in the space_allocation tables
85e485502dSkrw  *       requires corresponding updates to the *.ok files in
86e485502dSkrw  *	 /usr/src/regress/sbin/disklabel.
87e485502dSkrw  */
88e485502dSkrw 
898dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
90a2c1f847Shenning struct space_allocation alloc_big[] = {
91d190517aSotto 	{  MEG(150),         GIG(1),   5, "/"		},
92559340afSotto 	{   MEG(80),       MEG(256),  10, "swap"	},
934ab111d2Sderaadt 	{  MEG(120),         GIG(4),   8, "/tmp"	},
9492adb55fSderaadt 	{   MEG(80),         GIG(4),  13, "/var"	},
9526e633f4Sotto 	{ MEG(1500),         GIG(6),  10, "/usr"	},
96ecf06799Sajacoutot 	{  MEG(384),         GIG(1),   3, "/usr/X11R6"	},
9797f090a4Ssolene 	{    GIG(1),        GIG(20),  15, "/usr/local"	},
98aa4db624Sbenno 	{ MEG(1300),         GIG(2),   2, "/usr/src"	},
99d6b9791fSbluhm 	{    GIG(5),         GIG(6),   4, "/usr/obj"	},
10026e633f4Sotto 	{    GIG(1),       GIG(300),  30, "/home"	}
1014ab111d2Sderaadt 	/* Anything beyond this leave for the user to decide */
1028dde8bb6Sotto };
1038dde8bb6Sotto 
104a2c1f847Shenning struct space_allocation alloc_medium[] = {
105905e8239Sderaadt 	{  MEG(800),         GIG(2),   5, "/"		},
1068dde8bb6Sotto 	{   MEG(80),       MEG(256),  10, "swap"	},
107ad1fb99dSphessler 	{ MEG(1300),         GIG(3),  78, "/usr"	},
108905e8239Sderaadt 	{  MEG(256),         GIG(2),   7, "/home"	}
1098dde8bb6Sotto };
1108dde8bb6Sotto 
111a2c1f847Shenning struct space_allocation alloc_small[] = {
11292adb55fSderaadt 	{  MEG(700),         GIG(4),  95, "/"		},
1138dde8bb6Sotto 	{    MEG(1),       MEG(256),   5, "swap"	}
1148dde8bb6Sotto };
1158dde8bb6Sotto 
116a2c1f847Shenning struct space_allocation alloc_stupid[] = {
1178dde8bb6Sotto 	{    MEG(1),      MEG(2048), 100, "/"		}
1188dde8bb6Sotto };
1198dde8bb6Sotto 
120b2813ff1Sderaadt #ifndef nitems
121b2813ff1Sderaadt #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
122b2813ff1Sderaadt #endif
123b2813ff1Sderaadt 
124a2c1f847Shenning struct alloc_table {
125a2c1f847Shenning 	struct space_allocation *table;
1268a862940Sderaadt 	int sz;
127a2c1f847Shenning };
128a2c1f847Shenning 
129a2c1f847Shenning struct alloc_table alloc_table_default[] = {
1308dde8bb6Sotto 	{ alloc_big,	nitems(alloc_big) },
1318dde8bb6Sotto 	{ alloc_medium,	nitems(alloc_medium) },
1328dde8bb6Sotto 	{ alloc_small,	nitems(alloc_small) },
1338dde8bb6Sotto 	{ alloc_stupid,	nitems(alloc_stupid) }
134557f712bSkrw };
135a2c1f847Shenning struct alloc_table *alloc_table = alloc_table_default;
136f55524eaSsthen int alloc_table_nitems = 4;
137557f712bSkrw 
1389fdcb4d6Skrw void	edit_parms(struct disklabel *);
1396aaa4aabSotto void	editor_resize(struct disklabel *, char *);
14034ae4198Skrw void	editor_add(struct disklabel *, char *);
1419fdcb4d6Skrw void	editor_change(struct disklabel *, char *);
1429fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *);
14334ae4198Skrw void	editor_delete(struct disklabel *, char *);
1444d812bb6Slum void	editor_help(void);
14534ae4198Skrw void	editor_modify(struct disklabel *, char *);
14634ae4198Skrw void	editor_name(struct disklabel *, char *);
147b228e876Smiod char	*getstring(const char *, const char *, const char *);
14840b226e8Skrw u_int64_t getuint64(struct disklabel *, char *, char *, u_int64_t,
14940b226e8Skrw     u_int64_t, int *);
1500db7769aSkrw u_int64_t getnumber(char *, char *, u_int32_t, u_int32_t);
1511f0f871dSkrw int	has_overlap(struct disklabel *);
152c72b5b24Smillert int	partition_cmp(const void *, const void *);
1530fbd3c97Skrw struct partition **sort_partitions(struct disklabel *);
154c72b5b24Smillert void	getdisktype(struct disklabel *, char *, char *);
15587023ed9Skrw void	find_bounds(struct disklabel *);
1569fdcb4d6Skrw void	set_bounds(struct disklabel *);
15769a6ffbcSjsing void	set_duid(struct disklabel *);
158c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *);
159c72b5b24Smillert int	micmp(const void *, const void *);
160c72b5b24Smillert int	mpequal(char **, char **);
161c72b5b24Smillert int	get_bsize(struct disklabel *, int);
162c72b5b24Smillert int	get_fsize(struct disklabel *, int);
163a95dd767Sotto int	get_cpg(struct disklabel *, int);
164c72b5b24Smillert int	get_fstype(struct disklabel *, int);
16534ae4198Skrw int	get_mp(struct disklabel *, int);
166604d3bdeSkrw int	get_offset(struct disklabel *, int);
1679fdcb4d6Skrw int	get_size(struct disklabel *, int);
16887023ed9Skrw void	get_geometry(int, struct disklabel **);
16987023ed9Skrw void	set_geometry(struct disklabel *, struct disklabel *, struct disklabel *,
17087023ed9Skrw     char *);
1719fdcb4d6Skrw void	zero_partitions(struct disklabel *);
17214192793Skrw u_int64_t max_partition_size(struct disklabel *, int);
1737ad973c1Skrw void	display_edit(struct disklabel *, char);
174e07939ebSderaadt void	psize(u_int64_t sz, char unit, struct disklabel *lp);
17558c7d7acSnaddy char	*get_token(char **);
176a2c1f847Shenning int	apply_unit(double, u_char, u_int64_t *);
177a2c1f847Shenning int	parse_sizespec(const char *, double *, char **);
178a2c1f847Shenning int	parse_sizerange(char *, u_int64_t *, u_int64_t *);
179a2c1f847Shenning int	parse_pct(char *, int *);
18040b226e8Skrw int	alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int);
18196a888c6Smillert 
1821e0ad43cSotto static u_int64_t starting_sector;
1831e0ad43cSotto static u_int64_t ending_sector;
1842d8451b0Smillert static int expert;
185fc6e9c48Sotto static int overlap;
1866fe57b42Smillert 
1876fe57b42Smillert /*
1884d4a335eSkrw  * Simple partition editor.
1896fe57b42Smillert  */
1906fe57b42Smillert int
191d6d80bb0Skrw editor(int f)
1926fe57b42Smillert {
193d6d80bb0Skrw 	struct disklabel origlabel, lastlabel, tmplabel, newlab = lab;
1947e28fb0fSderaadt 	struct disklabel *disk_geop = NULL;
19596a888c6Smillert 	struct partition *pp;
1966fe57b42Smillert 	FILE *fp;
1976fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
19834ae4198Skrw 	char **omountpoints = NULL;
1994f3bbbf0Skrw 	char **origmountpoints = NULL, **tmpmountpoints = NULL;
2007e28fb0fSderaadt 	int i, error = 0;
201bd6726faSmillert 
202bd6726faSmillert 	/* Alloc and init mount point info */
20334ae4198Skrw 	if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
2044f3bbbf0Skrw 	    !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
205bd6726faSmillert 	    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
206bd6726faSmillert 		errx(4, "out of memory");
2076fe57b42Smillert 
20896a888c6Smillert 	/* Don't allow disk type of "unknown" */
209430e1380Skrw 	getdisktype(&newlab, "You need to specify a type for this disk.",
210430e1380Skrw 	    specname);
2116fe57b42Smillert 
21287023ed9Skrw 	/* Get the on-disk geometries if possible */
21387023ed9Skrw 	get_geometry(f, &disk_geop);
214c33fcabaSmillert 
215d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
216d6d80bb0Skrw 	find_bounds(&newlab);
217d09f3941Smillert 
21896a888c6Smillert 	/* Make sure there is no partition overlap. */
219d6d80bb0Skrw 	if (has_overlap(&newlab))
2206fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
2216fe57b42Smillert 
22296a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
223d6d80bb0Skrw 	pp = &newlab.d_partitions[RAW_PART];
224d6d80bb0Skrw 	if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) {
22596a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
226d6d80bb0Skrw 		if (newlab.d_npartitions < 3)
227d6d80bb0Skrw 			newlab.d_npartitions = 3;
22834af67a3Sotto 		DL_SETPOFFSET(pp, 0);
229d6d80bb0Skrw 		DL_SETPSIZE(pp, DL_GETDSIZE(&newlab));
23096a888c6Smillert 		pp->p_fstype = FS_UNUSED;
231ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
23296a888c6Smillert 	}
2330f820bbbSmillert 
234fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
2354bf1fc9dSotto 	if ((newlab.d_flags & D_VENDOR) && !quiet) {
236fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
237fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
238fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
239fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
240fc1a4cc6Sderaadt 	}
2416fe57b42Smillert #endif
2426fe57b42Smillert 
243bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
244d6d80bb0Skrw 	if (newlab.d_bbsize == 0)
245d6d80bb0Skrw 		newlab.d_bbsize = BBSIZE;
246d6d80bb0Skrw 	if (newlab.d_sbsize == 0)
247d6d80bb0Skrw 		newlab.d_sbsize = SBSIZE;
248f98aebd4Smillert 
24993160b9bSkrw 	/* Save the (U|u)ndo labels and mountpoints. */
25093160b9bSkrw 	mpcopy(origmountpoints, mountpoints);
251d6d80bb0Skrw 	origlabel = newlab;
252d6d80bb0Skrw 	lastlabel = newlab;
25334ae4198Skrw 
25434ae4198Skrw 	puts("Label editor (enter '?' for help at any prompt)");
2556fe57b42Smillert 	for (;;) {
256cbfc0aa2Skrw 		fprintf(stdout, "%s%s%c ", dkname,
257cbfc0aa2Skrw 		    (memcmp(&lab, &newlab, sizeof(newlab)) == 0) ? "" : "*",
258cbfc0aa2Skrw 		    (expert == 0) ? '>' : '#');
2596e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2606e0becc5Smillert 			putchar('\n');
2616e0becc5Smillert 			buf[0] = 'q';
2626e0becc5Smillert 			buf[1] = '\0';
2636e0becc5Smillert 		}
264260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
265260513deSmillert 			continue;
266260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2676fe57b42Smillert 
2684f3bbbf0Skrw 		if ((*cmd != 'u') && (*cmd != 'U')) {
2694f3bbbf0Skrw 			/*
2704f3bbbf0Skrw 			 * Save undo info in case the command tries to make
2714f3bbbf0Skrw 			 * changes but decides not to.
2724f3bbbf0Skrw 			 */
2734f3bbbf0Skrw 			tmplabel = lastlabel;
274d6d80bb0Skrw 			lastlabel = newlab;
2754f3bbbf0Skrw 			mpcopy(tmpmountpoints, omountpoints);
2764f3bbbf0Skrw 			mpcopy(omountpoints, mountpoints);
2774f3bbbf0Skrw 		}
2786fe57b42Smillert 
2794f3bbbf0Skrw 		switch (*cmd) {
2806fe57b42Smillert 		case '?':
281ea37abd3Sderaadt 		case 'h':
2824d812bb6Slum 			editor_help();
2836fe57b42Smillert 			break;
2846fe57b42Smillert 
285557f712bSkrw 		case 'A':
28690b0764fSkrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == -1) {
28790b0764fSkrw 				warn("DIOCGPDINFO");
28890b0764fSkrw 				newlab = lastlabel;
28990b0764fSkrw 			} else {
29040b226e8Skrw 				int oquiet = quiet, oexpert = expert;
2914bf1fc9dSotto 				aflag = 1;
29240b226e8Skrw 				quiet = expert = 0;
293d6d80bb0Skrw 				editor_allocspace(&newlab);
29440b226e8Skrw 				quiet = oquiet;
29540b226e8Skrw 				expert = oexpert;
29690b0764fSkrw 			}
297557f712bSkrw 			break;
2986fe57b42Smillert 		case 'a':
299d6d80bb0Skrw 			editor_add(&newlab, arg);
30096a888c6Smillert 			break;
30196a888c6Smillert 
30296a888c6Smillert 		case 'b':
303d6d80bb0Skrw 			set_bounds(&newlab);
3046fe57b42Smillert 			break;
3056fe57b42Smillert 
3066fe57b42Smillert 		case 'c':
307d6d80bb0Skrw 			editor_change(&newlab, arg);
3086fe57b42Smillert 			break;
3096fe57b42Smillert 
3109afbe9eeSmillert 		case 'D':
31190b0764fSkrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == -1)
31290b0764fSkrw 				warn("DIOCGPDINFO");
31390b0764fSkrw 			else {
31471bba4ecSkrw 				dflag = 1;
31593160b9bSkrw 				for (i = 0; i < MAXPARTITIONS; i++) {
31693160b9bSkrw 					free(mountpoints[i]);
31793160b9bSkrw 					mountpoints[i] = NULL;
31893160b9bSkrw 				}
31990b0764fSkrw 			}
3209afbe9eeSmillert 			break;
3219afbe9eeSmillert 
3226fe57b42Smillert 		case 'd':
323d6d80bb0Skrw 			editor_delete(&newlab, arg);
3246fe57b42Smillert 			break;
3256fe57b42Smillert 
3269afbe9eeSmillert 		case 'e':
327d6d80bb0Skrw 			edit_parms(&newlab);
3289afbe9eeSmillert 			break;
3299afbe9eeSmillert 
330c33fcabaSmillert 		case 'g':
331d6d80bb0Skrw 			set_geometry(&newlab, disk_geop, &lab, arg);
332c33fcabaSmillert 			break;
333c33fcabaSmillert 
3340d63cfbaSjsing 		case 'i':
335d6d80bb0Skrw 			set_duid(&newlab);
3360d63cfbaSjsing 			break;
3370d63cfbaSjsing 
3386fe57b42Smillert 		case 'm':
339d6d80bb0Skrw 			editor_modify(&newlab, arg);
340bd6726faSmillert 			break;
341bd6726faSmillert 
342bd6726faSmillert 		case 'n':
3435c79e1cfSkrw 			if (!fstabfile) {
344bd6726faSmillert 				fputs("This option is not valid when run "
3456b27d9e0Sjmc 				    "without the -F or -f flags.\n", stderr);
346bd6726faSmillert 				break;
347bd6726faSmillert 			}
348d6d80bb0Skrw 			editor_name(&newlab, arg);
3496fe57b42Smillert 			break;
3506fe57b42Smillert 
3516fe57b42Smillert 		case 'p':
3527ad973c1Skrw 			display_edit(&newlab, arg ? *arg : 0);
3536fe57b42Smillert 			break;
3546fe57b42Smillert 
355aff3f969Sotto 		case 'l':
356d6d80bb0Skrw 			display(stdout, &newlab, arg ? *arg : 0, 0);
357aff3f969Sotto 			break;
358aff3f969Sotto 
359508086e9Smillert 		case 'M': {
360508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
36145decb36Sderaadt 			char *pager, *comm = NULL;
362e7936562Sderaadt 			extern const u_char manpage[];
36308f8e31fSotto 			extern const int manpage_sz;
3645d12b01bSderaadt 
365489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
366508086e9Smillert 				pager = _PATH_LESS;
36708f8e31fSotto 
36845decb36Sderaadt 			if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
36945decb36Sderaadt 			    (fp = popen(comm, "w")) != NULL) {
37008f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3715d12b01bSderaadt 				pclose(fp);
372508086e9Smillert 			} else
373508086e9Smillert 				warn("unable to execute %s", pager);
374508086e9Smillert 
37545decb36Sderaadt 			free(comm);
376508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3775d12b01bSderaadt 			break;
378508086e9Smillert 		}
3795d12b01bSderaadt 
3806fe57b42Smillert 		case 'q':
38169220492Smillert 			if (donothing) {
38269220492Smillert 				puts("In no change mode, not writing label.");
3837e28fb0fSderaadt 				goto done;
38469220492Smillert 			}
38593160b9bSkrw 
38671bba4ecSkrw 			/*
38793160b9bSkrw 			 * If we haven't changed the original label, and it
38893160b9bSkrw 			 * wasn't a default label or an auto-allocated label,
38993160b9bSkrw 			 * there is no need to do anything before exiting. Note
39093160b9bSkrw 			 * that 'w' will reset dflag and aflag to allow 'q' to
39193160b9bSkrw 			 * exit without further questions.
39271bba4ecSkrw 			 */
393ab20a3eaSkrw 			if (!dflag && !aflag &&
394d6d80bb0Skrw 			    memcmp(&lab, &newlab, sizeof(newlab)) == 0) {
395bd6726faSmillert 				puts("No label changes.");
396d6d80bb0Skrw 				/* Save mountpoint info. */
397d6d80bb0Skrw 				mpsave(&newlab);
3987e28fb0fSderaadt 				goto done;
3996fe57b42Smillert 			}
4006fe57b42Smillert 			do {
401d0e67762Smillert 				arg = getstring("Write new label?",
402d0e67762Smillert 				    "Write the modified label to disk?",
403d0e67762Smillert 				    "y");
404025f5691Sderaadt 			} while (arg && tolower((unsigned char)*arg) != 'y' &&
405025f5691Sderaadt 			    tolower((unsigned char)*arg) != 'n');
406025f5691Sderaadt 			if (arg && tolower((unsigned char)*arg) == 'y') {
40740bba581Skrw 				if (writelabel(f, &newlab) == 0) {
408d6d80bb0Skrw 					newlab = lab; /* lab now has UID info */
4097e28fb0fSderaadt 					goto done;
4106fe57b42Smillert 				}
411d0e67762Smillert 				warnx("unable to write label");
412d0e67762Smillert 			}
4137e28fb0fSderaadt 			error = 1;
4147e28fb0fSderaadt 			goto done;
4156fe57b42Smillert 			/* NOTREACHED */
4166fe57b42Smillert 			break;
4176fe57b42Smillert 
4186aaa4aabSotto 		case 'R':
419fc6e9c48Sotto 			if (aflag && !overlap)
420d6d80bb0Skrw 				editor_resize(&newlab, arg);
4216aaa4aabSotto 			else
4226aaa4aabSotto 				fputs("Resize only implemented for auto "
423fc6e9c48Sotto 				    "allocated labels\n", stderr);
4246aaa4aabSotto 			break;
4256aaa4aabSotto 
42625f9c360Skrw 		case 'r': {
42725f9c360Skrw 			struct diskchunk *chunks;
42825f9c360Skrw 			int i;
4299fdcb4d6Skrw 			/* Display free space. */
430d6d80bb0Skrw 			chunks = free_chunks(&newlab);
43125f9c360Skrw 			for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0;
43225f9c360Skrw 			    i++)
43325f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
43425f9c360Skrw 				    "(%16llu)\n",
43525f9c360Skrw 				    chunks[i].start, chunks[i].stop - 1,
43625f9c360Skrw 				    chunks[i].stop - chunks[i].start);
43725f9c360Skrw 			fprintf(stderr, "Total free sectors: %llu.\n",
438d6d80bb0Skrw 			    editor_countfree(&newlab));
439c0bdc608Smillert 			break;
44025f9c360Skrw 		}
441c0bdc608Smillert 
4426fe57b42Smillert 		case 's':
4436fe57b42Smillert 			if (arg == NULL) {
444c33fcabaSmillert 				arg = getstring("Filename",
4456fe57b42Smillert 				    "Name of the file to save label into.",
4466fe57b42Smillert 				    NULL);
447e97229a3Scnst 				if (arg == NULL || *arg == '\0')
4486fe57b42Smillert 					break;
4496fe57b42Smillert 			}
4506fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
4516fe57b42Smillert 				warn("cannot open %s", arg);
4526fe57b42Smillert 			} else {
453d6d80bb0Skrw 				display(fp, &newlab, 0, 1);
4546fe57b42Smillert 				(void)fclose(fp);
4556fe57b42Smillert 			}
4566fe57b42Smillert 			break;
4576fe57b42Smillert 
4584f3bbbf0Skrw 		case 'U':
45993160b9bSkrw 			/*
460430e1380Skrw 			 * If we allow 'U' repeatedly, information would be
461430e1380Skrw 			 * lost. This way multiple 'U's followed by 'u' will
462430e1380Skrw 			 * undo the 'U's.
46393160b9bSkrw 			 */
464d6d80bb0Skrw 			if (memcmp(&newlab, &origlabel, sizeof(newlab)) ||
46593160b9bSkrw 			    !mpequal(mountpoints, origmountpoints)) {
466d6d80bb0Skrw 				tmplabel = newlab;
467d6d80bb0Skrw 				newlab = origlabel;
4684f3bbbf0Skrw 				lastlabel = tmplabel;
4694f3bbbf0Skrw 				mpcopy(tmpmountpoints, mountpoints);
4704f3bbbf0Skrw 				mpcopy(mountpoints, origmountpoints);
4714f3bbbf0Skrw 				mpcopy(omountpoints, tmpmountpoints);
4724f3bbbf0Skrw 			}
47393160b9bSkrw 			puts("Original label and mount points restored.");
4744f3bbbf0Skrw 			break;
4754f3bbbf0Skrw 
4766fe57b42Smillert 		case 'u':
477d6d80bb0Skrw 			tmplabel = newlab;
478d6d80bb0Skrw 			newlab = lastlabel;
4796fe57b42Smillert 			lastlabel = tmplabel;
4804f3bbbf0Skrw 			mpcopy(tmpmountpoints, mountpoints);
481bd6726faSmillert 			mpcopy(mountpoints, omountpoints);
4824f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4836fe57b42Smillert 			puts("Last change undone.");
4846fe57b42Smillert 			break;
4856fe57b42Smillert 
486040947cfSmillert 		case 'w':
487bd6726faSmillert 			if (donothing)  {
488040947cfSmillert 				puts("In no change mode, not writing label.");
489bd6726faSmillert 				break;
490bd6726faSmillert 			}
49193160b9bSkrw 
49241f684b9Skrw 			/* Write label to disk. */
49340bba581Skrw 			if (writelabel(f, &newlab) != 0)
494040947cfSmillert 				warnx("unable to write label");
49571bba4ecSkrw 			else {
496ab20a3eaSkrw 				dflag = aflag = 0;
497d6d80bb0Skrw 				newlab = lab; /* lab now has UID info */
49871bba4ecSkrw 			}
499040947cfSmillert 			break;
500040947cfSmillert 
5012d8451b0Smillert 		case 'X':
5022d8451b0Smillert 			expert = !expert;
5032d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
5042d8451b0Smillert 			    "Exiting");
5052d8451b0Smillert 			break;
5062d8451b0Smillert 
5076fe57b42Smillert 		case 'x':
5087e28fb0fSderaadt 			goto done;
5096fe57b42Smillert 			break;
5106fe57b42Smillert 
5119afbe9eeSmillert 		case 'z':
512d6d80bb0Skrw 			zero_partitions(&newlab);
5136fe57b42Smillert 			break;
5146fe57b42Smillert 
5159afbe9eeSmillert 		case '\n':
5166fe57b42Smillert 			break;
5176fe57b42Smillert 
5186fe57b42Smillert 		default:
5196fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
5206fe57b42Smillert 			break;
5216fe57b42Smillert 		}
5224f3bbbf0Skrw 
5234f3bbbf0Skrw 		/*
5244f3bbbf0Skrw 		 * If no changes were made to label or mountpoints, then
5254f3bbbf0Skrw 		 * restore undo info.
5264f3bbbf0Skrw 		 */
527d6d80bb0Skrw 		if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 &&
52893160b9bSkrw 		    (mpequal(mountpoints, omountpoints))) {
5294f3bbbf0Skrw 			lastlabel = tmplabel;
5304f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
5314f3bbbf0Skrw 		}
5326fe57b42Smillert 	}
5337e28fb0fSderaadt done:
534408ab9bcSkrw 	mpfree(omountpoints);
535408ab9bcSkrw 	mpfree(origmountpoints);
536408ab9bcSkrw 	mpfree(tmpmountpoints);
5377e28fb0fSderaadt 	free(disk_geop);
5387e28fb0fSderaadt 	return (error);
5396fe57b42Smillert }
5406fe57b42Smillert 
5416fe57b42Smillert /*
542557f712bSkrw  * Allocate all disk space according to standard recommendations for a
543557f712bSkrw  * root disk.
544557f712bSkrw  */
545185664b4Sotto int
5468dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
547557f712bSkrw {
5488dde8bb6Sotto 	struct disklabel *lp, label;
5498dde8bb6Sotto 	struct space_allocation *alloc;
55034ae4198Skrw 	struct space_allocation *ap;
551557f712bSkrw 	struct partition *pp;
55234ae4198Skrw 	struct diskchunk *chunks;
553859c13c7Skrw 	u_int64_t chunkstart, chunkstop, chunksize;
55459c4e6f1Skrw 	u_int64_t cylsecs, secs, xtrasecs;
55534ae4198Skrw 	char **partmp;
5563c723e85Skrw 	int i, j, lastalloc, index, partno, freeparts;
557e384f6efSderaadt 	extern int64_t physmem;
5588dde8bb6Sotto 
55934ae4198Skrw 	/* How big is the OpenBSD portion of the disk?  */
5608dde8bb6Sotto 	find_bounds(lp_org);
561557f712bSkrw 
562fc6e9c48Sotto 	overlap = 0;
5633c723e85Skrw 	freeparts = 0;
564fc6e9c48Sotto 	for (i = 0;  i < MAXPARTITIONS; i++) {
565eafadddfSkrw 		u_int64_t psz, pstart, pend;
566fc6e9c48Sotto 
567fc6e9c48Sotto 		pp = &lp_org->d_partitions[i];
568fc6e9c48Sotto 		psz = DL_GETPSIZE(pp);
5693c723e85Skrw 		if (psz == 0)
5703c723e85Skrw 			freeparts++;
571fc6e9c48Sotto 		pstart = DL_GETPOFFSET(pp);
572fc6e9c48Sotto 		pend = pstart + psz;
573fc6e9c48Sotto 		if (i != RAW_PART && psz != 0 &&
574fc6e9c48Sotto 		    ((pstart >= starting_sector && pstart <= ending_sector) ||
575fc6e9c48Sotto 		    (pend > starting_sector && pend < ending_sector))) {
576fc6e9c48Sotto 			overlap = 1;
577fc6e9c48Sotto 			break;
578fc6e9c48Sotto 		}
579fc6e9c48Sotto 	}
580fc6e9c48Sotto 
5818dde8bb6Sotto 	cylsecs = lp_org->d_secpercyl;
582598ec681Skrw 	alloc = NULL;
583598ec681Skrw 	index = -1;
5848dde8bb6Sotto again:
585598ec681Skrw 	free(alloc);
586a9e37dfeSkrw 	alloc = NULL;
587598ec681Skrw 	index++;
588598ec681Skrw 	if (index >= alloc_table_nitems)
589598ec681Skrw 		return 1;
5908dde8bb6Sotto 	lp = &label;
5913d98fc8cSkrw 	for (i=0; i<MAXPARTITIONS; i++) {
5923d98fc8cSkrw 		free(mountpoints[i]);
5933d98fc8cSkrw 		mountpoints[i] = NULL;
5943d98fc8cSkrw 	}
5958dde8bb6Sotto 	memcpy(lp, lp_org, sizeof(struct disklabel));
5960a7398ceSderaadt 	lp->d_npartitions = MAXPARTITIONS;
5978dde8bb6Sotto 	lastalloc = alloc_table[index].sz;
5983c723e85Skrw 	if (lastalloc > freeparts)
5993c723e85Skrw 		goto again;
600ab30cb2fSdoug 	alloc = reallocarray(NULL, lastalloc, sizeof(struct space_allocation));
6018dde8bb6Sotto 	if (alloc == NULL)
6028dde8bb6Sotto 		errx(4, "out of memory");
6038dde8bb6Sotto 	memcpy(alloc, alloc_table[index].table,
6048dde8bb6Sotto 	    lastalloc * sizeof(struct space_allocation));
6058dde8bb6Sotto 
6068dde8bb6Sotto 	/* bump max swap based on phys mem, little physmem gets 2x swap */
607a2c1f847Shenning 	if (index == 0 && alloc_table == alloc_table_default) {
608e384f6efSderaadt 		if (physmem / DEV_BSIZE < MEG(256))
609e0befca8Skrw 			alloc[1].minsz = alloc[1].maxsz = 2 * (physmem /
610e0befca8Skrw 			    DEV_BSIZE);
6118dde8bb6Sotto 		else
612e384f6efSderaadt 			alloc[1].maxsz += (physmem / DEV_BSIZE);
6138dde8bb6Sotto 		/* bump max /var to make room for 2 crash dumps */
614e384f6efSderaadt 		alloc[3].maxsz += 2 * (physmem / DEV_BSIZE);
6158dde8bb6Sotto 	}
6168dde8bb6Sotto 
61759c4e6f1Skrw 	xtrasecs = editor_countfree(lp);
618557f712bSkrw 
61934ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
6205f3e1104Skrw 		alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz);
6215f3e1104Skrw 		alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz);
6224f05c2ddSkrw 		if (xtrasecs >= alloc[i].minsz)
62334ae4198Skrw 			xtrasecs -= alloc[i].minsz;
6244f05c2ddSkrw 		else {
6254f05c2ddSkrw 			/* It did not work out, try next strategy */
6264f05c2ddSkrw 			goto again;
6274f05c2ddSkrw 		}
628557f712bSkrw 	}
629557f712bSkrw 
63034ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
63134ae4198Skrw 		/* Find next available partition. */
63234ae4198Skrw 		for (j = 0;  j < MAXPARTITIONS; j++)
63334ae4198Skrw 			if (DL_GETPSIZE(&lp->d_partitions[j]) == 0)
63434ae4198Skrw 				break;
635a243d7b5Skrw 		if (j == MAXPARTITIONS) {
636a243d7b5Skrw 			/* It did not work out, try next strategy */
637a243d7b5Skrw 			goto again;
638a243d7b5Skrw 		}
639a49bdda8Skrw 		partno = j;
64034ae4198Skrw 		pp = &lp->d_partitions[j];
64134ae4198Skrw 		partmp = &mountpoints[j];
64234ae4198Skrw 		ap = &alloc[i];
643557f712bSkrw 
64434ae4198Skrw 		/* Find largest chunk of free space. */
64534ae4198Skrw 		chunks = free_chunks(lp);
64634ae4198Skrw 		chunksize = 0;
647859c13c7Skrw 		for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) {
64834ae4198Skrw 			if ((chunks[j].stop - chunks[j].start) > chunksize) {
64934ae4198Skrw 				chunkstart = chunks[j].start;
650859c13c7Skrw 				chunkstop = chunks[j].stop;
65134ae4198Skrw #ifdef SUN_CYLCHECK
65234ae4198Skrw 				if (lp->d_flags & D_VENDOR) {
653859c13c7Skrw 					/* Align to cylinder boundaries. */
654859c13c7Skrw 					chunkstart = ((chunkstart + cylsecs - 1)
655859c13c7Skrw 					    / cylsecs) * cylsecs;
656859c13c7Skrw 					chunkstop = (chunkstop / cylsecs) *
6576ab0bb66Skrw 					    cylsecs;
65834ae4198Skrw 				}
65934ae4198Skrw #endif
660859c13c7Skrw 				chunksize = chunkstop - chunkstart;
661859c13c7Skrw 			}
662859c13c7Skrw 		}
663859c13c7Skrw 
66459c4e6f1Skrw 		/* Figure out the size of the partition. */
66559c4e6f1Skrw 		if (i == lastalloc - 1) {
66659c4e6f1Skrw 			if (chunksize > ap->maxsz)
66759c4e6f1Skrw 				secs = ap->maxsz;
66859c4e6f1Skrw 			else
66934ae4198Skrw 				secs = chunksize;
67059c4e6f1Skrw 		} else {
67159c4e6f1Skrw 			secs = ap->minsz;
67259c4e6f1Skrw 			if (xtrasecs > 0)
67359c4e6f1Skrw 				secs += (xtrasecs / 100) * ap->rate;
67459c4e6f1Skrw 			if (secs > ap->maxsz)
67559c4e6f1Skrw 				secs = ap->maxsz;
67634ae4198Skrw 		}
67759c4e6f1Skrw #ifdef SUN_CYLCHECK
67859c4e6f1Skrw 		if (lp->d_flags & D_VENDOR) {
67959c4e6f1Skrw 			secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
68059c4e6f1Skrw 			while (secs > chunksize)
68159c4e6f1Skrw 				secs -= cylsecs;
68259c4e6f1Skrw 		}
68359c4e6f1Skrw #endif
68459c4e6f1Skrw 
68559c4e6f1Skrw 		/* See if partition can fit into chunk. */
68659c4e6f1Skrw 		if (secs > chunksize)
68759c4e6f1Skrw 			secs = chunksize;
68834ae4198Skrw 		if (secs < ap->minsz) {
6898dde8bb6Sotto 			/* It did not work out, try next strategy */
6908dde8bb6Sotto 			goto again;
691557f712bSkrw 		}
69234ae4198Skrw 
69334ae4198Skrw 		/* Everything seems ok so configure the partition. */
6945f3e1104Skrw 		DL_SETPSIZE(pp, secs);
69534ae4198Skrw 		DL_SETPOFFSET(pp, chunkstart);
69634ae4198Skrw 		if (ap->mp[0] != '/')
69734ae4198Skrw 			pp->p_fstype = FS_SWAP;
69834ae4198Skrw 		else {
69934ae4198Skrw 			pp->p_fstype = FS_BSDFFS;
700d68164a2Skrw 			pp->p_fragblock = 0;
701d68164a2Skrw 			if (get_fsize(lp, partno) == 1 ||
702d68164a2Skrw 			    get_bsize(lp, partno) == 1 ||
703d68164a2Skrw 			    get_cpg(lp, partno) == 1) {
704d68164a2Skrw 				free(alloc);
705d68164a2Skrw 				return 1;
706d68164a2Skrw 			}
70734ae4198Skrw 			free(*partmp);
70834ae4198Skrw 			if ((*partmp = strdup(ap->mp)) == NULL)
709557f712bSkrw 				errx(4, "out of memory");
710557f712bSkrw 		}
711557f712bSkrw 	}
712557f712bSkrw 
7138dde8bb6Sotto 	free(alloc);
7148dde8bb6Sotto 	memcpy(lp_org, lp, sizeof(struct disklabel));
715185664b4Sotto 	return 0;
716557f712bSkrw }
717557f712bSkrw 
718557f712bSkrw /*
7196aaa4aabSotto  * Resize a partition, moving all subsequent partitions
7206aaa4aabSotto  */
7216aaa4aabSotto void
7226aaa4aabSotto editor_resize(struct disklabel *lp, char *p)
7236aaa4aabSotto {
7246aaa4aabSotto 	struct disklabel label;
7256aaa4aabSotto 	struct partition *pp, *prev;
726914b3475Skrw 	u_int64_t ui, sz, off;
72777370cdaSkrw 	int partno, i, flags, shrunk;
7286aaa4aabSotto 
7296aaa4aabSotto 	label = *lp;
7306aaa4aabSotto 
7316aaa4aabSotto 	/* Change which partition? */
732ac30837aSkrw 	if (p == NULL)
7336aaa4aabSotto 		p = getstring("partition to resize",
7346aaa4aabSotto 		    "The letter of the partition to name, a - p.", NULL);
735ac30837aSkrw 	if (p == NULL)
7366aaa4aabSotto 		return;
7376aaa4aabSotto 	partno = p[0] - 'a';
7386aaa4aabSotto 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
7396aaa4aabSotto 		fprintf(stderr, "Partition must be between 'a' and '%c' "
7406aaa4aabSotto 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
7416aaa4aabSotto 		return;
7426aaa4aabSotto 	}
7436aaa4aabSotto 
7446aaa4aabSotto 	pp = &label.d_partitions[partno];
745fc6e9c48Sotto 	sz = DL_GETPSIZE(pp);
746fc6e9c48Sotto 	if (sz == 0) {
747fc6e9c48Sotto 		fputs("No such partition\n", stderr);
748fc6e9c48Sotto 		return;
749fc6e9c48Sotto 	}
750fc6e9c48Sotto 	if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) {
751fc6e9c48Sotto 		fputs("Cannot resize spoofed partition\n", stderr);
752fc6e9c48Sotto 		return;
753fc6e9c48Sotto 	}
75440b226e8Skrw 	flags = DO_CONVERSIONS;
755914b3475Skrw 	ui = getuint64(lp, "[+|-]new size (with unit)",
756e0befca8Skrw 	    "new size or amount to grow (+) or shrink (-) partition including "
75740b226e8Skrw 	    "unit", sz, sz + editor_countfree(lp), &flags);
7586aaa4aabSotto 
759914b3475Skrw 	if (ui == CMD_ABORTED)
7606aaa4aabSotto 		return;
761914b3475Skrw 	else if (ui == CMD_BADVALUE)
7629f0bdc2aSkrw 		return;
763914b3475Skrw 	else if (ui == 0) {
7641298f28aSkrw 		fputs("The size must be > 0 sectors\n", stderr);
7651298f28aSkrw 		return;
7666aaa4aabSotto 	}
7676aaa4aabSotto 
7686aaa4aabSotto #ifdef SUN_CYLCHECK
7691298f28aSkrw 	if (lp->d_secpercyl & D_VENDOR) {
7701298f28aSkrw 		u_int64_t cylsecs;
7716aaa4aabSotto 		cylsecs = lp->d_secpercyl;
772ce0ca44bSkrw 		ui = ((ui + cylsecs - 1) / cylsecs) * cylsecs;
7731298f28aSkrw 	}
7746aaa4aabSotto #endif
775914b3475Skrw 	if (DL_GETPOFFSET(pp) + ui > ending_sector) {
7766aaa4aabSotto 		fputs("Amount too big\n", stderr);
7776aaa4aabSotto 		return;
7786aaa4aabSotto 	}
7796aaa4aabSotto 
780914b3475Skrw 	DL_SETPSIZE(pp, ui);
781d68164a2Skrw 	pp->p_fragblock = 0;
782d68164a2Skrw 	if (get_fsize(&label, partno) == 1 ||
783d68164a2Skrw 	    get_bsize(&label, partno) == 1 ||
784d68164a2Skrw 	    get_cpg(&label, partno) == 1)
785d68164a2Skrw 		return;
7866aaa4aabSotto 
7876aaa4aabSotto 	/*
7886aaa4aabSotto 	 * Pack partitions above the resized partition, leaving unused
789c7e00dc5Skrw 	 * partitions alone.
7906aaa4aabSotto 	 */
79177370cdaSkrw 	shrunk = -1;
7926aaa4aabSotto 	prev = pp;
7936aaa4aabSotto 	for (i = partno + 1; i < MAXPARTITIONS; i++) {
7946aaa4aabSotto 		if (i == RAW_PART)
7956aaa4aabSotto 			continue;
796fc6e9c48Sotto 		pp = &label.d_partitions[i];
797fc6e9c48Sotto 		if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP)
798fc6e9c48Sotto 			continue;
799fc6e9c48Sotto 		sz = DL_GETPSIZE(pp);
8006aaa4aabSotto 		if (sz == 0)
8016aaa4aabSotto 			continue;
8026aaa4aabSotto 
8036aaa4aabSotto 		off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
8046aaa4aabSotto 
8056aaa4aabSotto 		if (off < ending_sector) {
8066aaa4aabSotto 			DL_SETPOFFSET(pp, off);
8076aaa4aabSotto 			if (off + DL_GETPSIZE(pp) > ending_sector) {
8086aaa4aabSotto 				DL_SETPSIZE(pp, ending_sector - off);
809ad90a7d1Sotto 				pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(0, 0);
810ad90a7d1Sotto 				if (get_fsize(&label, i) == 1 ||
811ad90a7d1Sotto 				    get_bsize(&label, i) == 1 ||
812ad90a7d1Sotto 				    get_cpg(&label, i) == 1)
813d68164a2Skrw 					return;
81477370cdaSkrw 				shrunk = i;
8156aaa4aabSotto 			}
8166aaa4aabSotto 		} else {
81777370cdaSkrw 			fputs("Amount too big\n", stderr);
8186aaa4aabSotto 			return;
8196aaa4aabSotto 		}
8206aaa4aabSotto 		prev = pp;
8216aaa4aabSotto 	}
82277370cdaSkrw 
82377370cdaSkrw 	if (shrunk != -1)
82477370cdaSkrw 		fprintf(stderr, "Partition %c shrunk to %llu sectors to make "
82577370cdaSkrw 		    "room\n", 'a' + shrunk,
82677370cdaSkrw 		    DL_GETPSIZE(&label.d_partitions[shrunk]));
8276aaa4aabSotto 	*lp = label;
8286aaa4aabSotto }
8296aaa4aabSotto 
8306aaa4aabSotto /*
8316fe57b42Smillert  * Add a new partition.
8326fe57b42Smillert  */
8336fe57b42Smillert void
83434ae4198Skrw editor_add(struct disklabel *lp, char *p)
8356fe57b42Smillert {
83696a888c6Smillert 	struct partition *pp;
83796a888c6Smillert 	struct diskchunk *chunks;
8385caa08b2Skrw 	char buf[2];
839a3ad4147Skrw 	int i, partno;
840f8ab7229Schl 	u_int64_t freesectors, new_offset, new_size;
8419fdcb4d6Skrw 
8429fdcb4d6Skrw 	freesectors = editor_countfree(lp);
8436fe57b42Smillert 
8446fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
845fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
8469fdcb4d6Skrw 	if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) {
847fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
848fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
849fc1a4cc6Sderaadt 		    stderr);
850fc1a4cc6Sderaadt 		return;
851fc1a4cc6Sderaadt 	}
8528390cf28Smillert #endif
8539fdcb4d6Skrw 	if (freesectors == 0) {
8546fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
8556fe57b42Smillert 		    stderr);
8566fe57b42Smillert 		return;
8576fe57b42Smillert 	}
8586fe57b42Smillert 
8595caa08b2Skrw 	if (p == NULL) {
8605caa08b2Skrw 		/*
8615caa08b2Skrw 		 * Use the first unused partition that is not 'c' as the
8625caa08b2Skrw 		 * default partition in the prompt string.
8635caa08b2Skrw 		 */
8645caa08b2Skrw 		pp = &lp->d_partitions[0];
8655caa08b2Skrw 		buf[0] = buf[1] = '\0';
8665caa08b2Skrw 		for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) {
8675caa08b2Skrw 			if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) {
8685caa08b2Skrw 				buf[0] = partno + 'a';
8695caa08b2Skrw 				p = &buf[0];
8706fe57b42Smillert 				break;
8716fe57b42Smillert 			}
8725caa08b2Skrw 		}
873c33fcabaSmillert 		p = getstring("partition",
8746fe57b42Smillert 		    "The letter of the new partition, a - p.", p);
8756fe57b42Smillert 	}
876ac30837aSkrw 	if (p == NULL)
8775caa08b2Skrw 		return;
8785caa08b2Skrw 	partno = p[0] - 'a';
8795caa08b2Skrw 	if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) {
8805caa08b2Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
8815caa08b2Skrw 		    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
8825caa08b2Skrw 		return;
8835caa08b2Skrw 	}
8845caa08b2Skrw 	pp = &lp->d_partitions[partno];
8855caa08b2Skrw 
8865caa08b2Skrw 	if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) {
8875caa08b2Skrw 		fprintf(stderr, "Partition '%c' exists.  Delete it first.\n",
8885caa08b2Skrw 		    p[0]);
8895caa08b2Skrw 		return;
8906fe57b42Smillert 	}
89196a888c6Smillert 
892caf41f96Skrw 	/*
893caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
894855d4e83Ssobrado 	 * zero'ed to avoid inadvertent overlaps.
895caf41f96Skrw 	 */
896caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
897caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
89896a888c6Smillert 
89989f4601dSkrw 	/* Make sure selected partition is zero'd too. */
90089f4601dSkrw 	memset(pp, 0, sizeof(*pp));
90115c15d8aSkrw 	chunks = free_chunks(lp);
90215c15d8aSkrw 
90315c15d8aSkrw 	/*
90415c15d8aSkrw 	 * Since we know there's free space, there must be at least one
90515c15d8aSkrw 	 * chunk. So find the largest chunk and assume we want to add the
90615c15d8aSkrw 	 * partition in that free space.
90715c15d8aSkrw 	 */
90815c15d8aSkrw 	new_size = new_offset = 0;
90915c15d8aSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
91015c15d8aSkrw 		if (chunks[i].stop - chunks[i].start > new_size) {
91115c15d8aSkrw 			new_size = chunks[i].stop - chunks[i].start;
91215c15d8aSkrw 			new_offset = chunks[i].start;
91315c15d8aSkrw 		}
91415c15d8aSkrw 	}
9151e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
9161e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
91796a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
918c88f83bdSotto 
919c88f83bdSotto 	if (get_offset(lp, partno) == 0 &&
920a3ad4147Skrw 	    get_size(lp, partno) == 0 &&
921a3ad4147Skrw 	    get_fstype(lp, partno) == 0 &&
92234ae4198Skrw 	    get_mp(lp, partno) == 0 &&
923a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
924a6262855Skrw 	    get_bsize(lp, partno) == 0 &&
925a6262855Skrw 	    get_cpg(lp, partno) == 0)
92696a888c6Smillert 		return;
927a3ad4147Skrw 
928a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
929da2bd3f5Skrw 	memset(pp, 0, sizeof(*pp));
9306fe57b42Smillert }
9316fe57b42Smillert 
9326fe57b42Smillert /*
933bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
934bd6726faSmillert  */
935bd6726faSmillert void
93634ae4198Skrw editor_name(struct disklabel *lp, char *p)
937bd6726faSmillert {
938bd6726faSmillert 	struct partition *pp;
939bd6726faSmillert 	int partno;
940bd6726faSmillert 
941bd6726faSmillert 	/* Change which partition? */
942ac30837aSkrw 	if (p == NULL)
943c33fcabaSmillert 		p = getstring("partition to name",
944bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
945ac30837aSkrw 	if (p == NULL)
946bd6726faSmillert 		return;
947bd6726faSmillert 	partno = p[0] - 'a';
9486c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9496c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9506c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
951bd6726faSmillert 		return;
95266df1f0cSkrw 	}
95366df1f0cSkrw 	pp = &lp->d_partitions[partno];
95466df1f0cSkrw 
95566df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
95666df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
957bd6726faSmillert 		return;
958bd6726faSmillert 	}
959bd6726faSmillert 
96034ae4198Skrw 	get_mp(lp, partno);
961bd6726faSmillert }
962bd6726faSmillert 
963bd6726faSmillert /*
9646fe57b42Smillert  * Change an existing partition.
9656fe57b42Smillert  */
9666fe57b42Smillert void
96734ae4198Skrw editor_modify(struct disklabel *lp, char *p)
9686fe57b42Smillert {
96940b226e8Skrw 	struct partition opp, *pp;
970f8ab7229Schl 	int partno;
9716fe57b42Smillert 
9726fe57b42Smillert 	/* Change which partition? */
973ac30837aSkrw 	if (p == NULL)
974c33fcabaSmillert 		p = getstring("partition to modify",
9756fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
976ac30837aSkrw 	if (p == NULL)
97796a888c6Smillert 		return;
9786fe57b42Smillert 	partno = p[0] - 'a';
9796c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9806c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9816c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
9826fe57b42Smillert 		return;
98366df1f0cSkrw 	}
98466df1f0cSkrw 	pp = &lp->d_partitions[partno];
98566df1f0cSkrw 
98666df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
98766df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
9886fe57b42Smillert 		return;
9896fe57b42Smillert 	}
9906fe57b42Smillert 
99140b226e8Skrw 	opp = *pp;
99266df1f0cSkrw 
993a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
994a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
995a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
99634ae4198Skrw 	    get_mp(lp, partno) == 0 &&
997a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
998a95dd767Sotto 	    get_bsize(lp, partno) == 0 &&
999a95dd767Sotto 	    get_cpg(lp, partno) == 0)
100096a888c6Smillert 		return;
10016fe57b42Smillert 
1002a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
100340b226e8Skrw 	*pp = opp;
10046fe57b42Smillert }
10056fe57b42Smillert 
10066fe57b42Smillert /*
10076fe57b42Smillert  * Delete an existing partition.
10086fe57b42Smillert  */
10096fe57b42Smillert void
101034ae4198Skrw editor_delete(struct disklabel *lp, char *p)
10116fe57b42Smillert {
101266df1f0cSkrw 	struct partition *pp;
1013135c90d1Skrw 	int partno;
10146fe57b42Smillert 
1015ac30837aSkrw 	if (p == NULL)
1016c33fcabaSmillert 		p = getstring("partition to delete",
1017945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
1018945ae268Smillert 		    NULL);
1019ac30837aSkrw 	if (p == NULL)
102096a888c6Smillert 		return;
1021945ae268Smillert 	if (p[0] == '*') {
10229fdcb4d6Skrw 		zero_partitions(lp);
1023945ae268Smillert 		return;
1024945ae268Smillert 	}
1025135c90d1Skrw 	partno = p[0] - 'a';
1026135c90d1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10276c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10286c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
102933262abfSmiod 		return;
103066df1f0cSkrw 	}
1031135c90d1Skrw 	pp = &lp->d_partitions[partno];
103266df1f0cSkrw 
103366df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
103466df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
103533262abfSmiod 		return;
103666df1f0cSkrw 	}
103766df1f0cSkrw 
10386fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
1039135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
104034ae4198Skrw 	free(mountpoints[partno]);
104134ae4198Skrw 	mountpoints[partno] = NULL;
10426fe57b42Smillert }
10436fe57b42Smillert 
10446fe57b42Smillert /*
10456fe57b42Smillert  * Change the size of an existing partition.
10466fe57b42Smillert  */
10476fe57b42Smillert void
10489fdcb4d6Skrw editor_change(struct disklabel *lp, char *p)
10496fe57b42Smillert {
10504b9a3bdaSmillert 	struct partition *pp;
105166df1f0cSkrw 	int partno;
10526fe57b42Smillert 
1053ac30837aSkrw 	if (p == NULL)
1054c33fcabaSmillert 		p = getstring("partition to change size",
10556fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
1056ac30837aSkrw 	if (p == NULL)
105796a888c6Smillert 		return;
10586fe57b42Smillert 	partno = p[0] - 'a';
10596c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10606c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10616c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
10626fe57b42Smillert 		return;
10636fe57b42Smillert 	}
10644b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
10656fe57b42Smillert 
106666df1f0cSkrw 	if (DL_GETPSIZE(pp) == 0) {
106766df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
106866df1f0cSkrw 		return;
106966df1f0cSkrw 	}
107066df1f0cSkrw 
107114192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
107214192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
107314192793Skrw 	    p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno));
10747da73705Skrw 
107559ccf790Skrw 	/* Get new size */
10769fdcb4d6Skrw 	get_size(lp, partno);
10776fe57b42Smillert }
10786fe57b42Smillert 
10796fe57b42Smillert /*
10806fe57b42Smillert  * Sort the partitions based on starting offset.
10816fe57b42Smillert  * This assumes there can be no overlap.
10826fe57b42Smillert  */
10836fe57b42Smillert int
10848809fabbSderaadt partition_cmp(const void *e1, const void *e2)
10856fe57b42Smillert {
10866fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10876fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10881e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
10891e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
10906fe57b42Smillert 
10911e0ad43cSotto 	if (o1 < o2)
1092651d5bd9Sotto 		return -1;
10931e0ad43cSotto 	else if (o1 > o2)
1094651d5bd9Sotto 		return 1;
1095651d5bd9Sotto 	else
1096651d5bd9Sotto 		return 0;
10976fe57b42Smillert }
10986fe57b42Smillert 
10996fe57b42Smillert char *
1100b228e876Smiod getstring(const char *prompt, const char *helpstring, const char *oval)
11016fe57b42Smillert {
11026fe57b42Smillert 	static char buf[BUFSIZ];
11036fe57b42Smillert 	int n;
11046fe57b42Smillert 
11056fe57b42Smillert 	buf[0] = '\0';
11066fe57b42Smillert 	do {
11076fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
11086e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1109260513deSmillert 			buf[0] = '\0';
111096a888c6Smillert 			if (feof(stdin)) {
111124c6582eSmillert 				clearerr(stdin);
111296a888c6Smillert 				putchar('\n');
1113ac30837aSkrw 				fputs("Command aborted\n", stderr);
111496a888c6Smillert 				return (NULL);
111596a888c6Smillert 			}
11166e0becc5Smillert 		}
11176fe57b42Smillert 		n = strlen(buf);
11186fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11196fe57b42Smillert 			buf[--n] = '\0';
11206fe57b42Smillert 		if (buf[0] == '?')
11216fe57b42Smillert 			puts(helpstring);
11224fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
11234fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
11246fe57b42Smillert 	} while (buf[0] == '?');
11256fe57b42Smillert 
11266fe57b42Smillert 	return (&buf[0]);
11276fe57b42Smillert }
11286fe57b42Smillert 
11296fe57b42Smillert /*
1130aa3970cdSkrw  * Returns
1131aa3970cdSkrw  * 0 .. CMD_ABORTED - 1	==> valid value
1132aa3970cdSkrw  * CMD_BADVALUE		==> invalid value
1133aa3970cdSkrw  * CMD_ABORTED		==> ^D on input
11346fe57b42Smillert  */
11351e0ad43cSotto u_int64_t
11360db7769aSkrw getnumber(char *prompt, char *helpstring, u_int32_t oval, u_int32_t maxval)
11370db7769aSkrw {
11380db7769aSkrw 	char buf[BUFSIZ], *p;
11390db7769aSkrw 	int rslt;
11400db7769aSkrw 	long long rval;
11410db7769aSkrw 	const char *errstr;
11420db7769aSkrw 
11430db7769aSkrw 	rslt = snprintf(buf, sizeof(buf), "%u", oval);
1144515e489cSderaadt 	if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
11450db7769aSkrw 		return (CMD_BADVALUE);
11460db7769aSkrw 
11470db7769aSkrw 	p = getstring(prompt, helpstring, buf);
11480db7769aSkrw 	if (p == NULL)
11490db7769aSkrw 		return (CMD_ABORTED);
11500db7769aSkrw 	if (strlen(p) == 0)
11510db7769aSkrw 		return (oval);
11520db7769aSkrw 
11530db7769aSkrw 	rval = strtonum(p, 0, maxval, &errstr);
11540db7769aSkrw 	if (errstr != NULL) {
11550db7769aSkrw 		printf("%s must be between 0 and %u\n", prompt, maxval);
11560db7769aSkrw 		return (CMD_BADVALUE);
11570db7769aSkrw 	}
11580db7769aSkrw 
11590db7769aSkrw 	return (rval);
11600db7769aSkrw }
11610db7769aSkrw 
11620db7769aSkrw /*
11630db7769aSkrw  * Returns
11640db7769aSkrw  * 0 .. CMD_ABORTED - 1	==> valid value
11650db7769aSkrw  * CMD_BADVALUE		==> invalid value
11660db7769aSkrw  * CMD_ABORTED		==> ^D on input
11670db7769aSkrw  */
11680db7769aSkrw u_int64_t
1169117239d3Skrw getuint64(struct disklabel *lp, char *prompt, char *helpstring,
117040b226e8Skrw     u_int64_t oval, u_int64_t maxval, int *flags)
11716fe57b42Smillert {
11721fec2892Skrw 	char buf[21], *p, operator = '\0';
11731fec2892Skrw 	char *unit = NULL;
11741e0ad43cSotto 	u_int64_t rval = oval;
11751fec2892Skrw 	double d;
11769a4afaafSkrw 	int rslt;
11776fe57b42Smillert 
11789a4afaafSkrw 	rslt = snprintf(buf, sizeof(buf), "%llu", oval);
1179515e489cSderaadt 	if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
11809a4afaafSkrw 		goto invalid;
11819a4afaafSkrw 
11829a4afaafSkrw 	p = getstring(prompt, helpstring, buf);
11839a4afaafSkrw 	if (p == NULL)
1184aa3970cdSkrw 		return (CMD_ABORTED);
11851fec2892Skrw 	else if (p[0] == '\0')
11861fec2892Skrw 		rval = oval;
11871fec2892Skrw 	else if (p[0] == '*' && p[1] == '\0')
11886fe57b42Smillert 		rval = maxval;
11891fec2892Skrw 	else {
11901fec2892Skrw 		if (*p == '+' || *p == '-')
11911fec2892Skrw 			operator = *p++;
11921fec2892Skrw 		if (parse_sizespec(p, &d, &unit) == -1)
11931fec2892Skrw 			goto invalid;
11941fec2892Skrw 		if (unit == NULL)
11951fec2892Skrw 			rval = d;
11961fec2892Skrw 		else if (flags != NULL && (*flags & DO_CONVERSIONS) == 0)
11971fec2892Skrw 			goto invalid;
11981fec2892Skrw 		else {
11991fec2892Skrw 			switch (tolower((unsigned char)*unit)) {
12006fe57b42Smillert 			case 'b':
12011fec2892Skrw 				rval = d / lp->d_secsize;
12026fe57b42Smillert 				break;
12031fec2892Skrw 			case 'c':
12041fec2892Skrw 				rval = d * lp->d_secpercyl;
12051a51a1eeSmillert 				break;
120614cc915fSmillert 			case '%':
12071fec2892Skrw 				rval = DL_GETDSIZE(lp) * (d / 100.0);
120814cc915fSmillert 				break;
120914cc915fSmillert 			case '&':
12101fec2892Skrw 				rval = maxval * (d / 100.0);
12111fec2892Skrw 				break;
12121fec2892Skrw 			default:
12131fec2892Skrw 				if (apply_unit(d, *unit, &rval) == -1)
12141fec2892Skrw 					goto invalid;
12151fec2892Skrw 				rval = DL_BLKTOSEC(lp, rval);
121614cc915fSmillert 				break;
12176fe57b42Smillert 			}
121896a888c6Smillert 		}
12196fe57b42Smillert 
1220e15dcdb4Skrw 		/* Range check then apply [+-] operator */
1221e15dcdb4Skrw 		if (operator == '+') {
1222aa3970cdSkrw 			if (CMD_ABORTED - oval > rval)
12236fe57b42Smillert 				rval += oval;
1224e15dcdb4Skrw 			else {
1225ac30837aSkrw 				goto invalid;
1226e15dcdb4Skrw 			}
1227e15dcdb4Skrw 		} else if (operator == '-') {
1228e15dcdb4Skrw 			if (oval >= rval)
12296fe57b42Smillert 				rval = oval - rval;
1230e15dcdb4Skrw 			else {
1231ac30837aSkrw 				goto invalid;
1232e15dcdb4Skrw 			}
1233e15dcdb4Skrw 		}
12346fe57b42Smillert 	}
123540b226e8Skrw 
123640b226e8Skrw 	if (flags != NULL) {
12371fec2892Skrw 		if (unit != NULL)
123840b226e8Skrw 			*flags |= DO_ROUNDING;
1239fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
124040b226e8Skrw 		if (lp->d_flags & D_VENDOR)
124140b226e8Skrw 			*flags |= DO_ROUNDING;
1242dbffb156Smillert #endif
12436fe57b42Smillert 	}
12446fe57b42Smillert 	return (rval);
1245ac30837aSkrw 
1246ac30837aSkrw invalid:
1247ac30837aSkrw 	fputs("Invalid entry\n", stderr);
1248aa3970cdSkrw 	return (CMD_BADVALUE);
12496fe57b42Smillert }
12506fe57b42Smillert 
12516fe57b42Smillert /*
12521f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
12531f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
12546fe57b42Smillert  */
12556fe57b42Smillert int
12561f0f871dSkrw has_overlap(struct disklabel *lp)
12576fe57b42Smillert {
12586fe57b42Smillert 	struct partition **spp;
12590f1cd5a2Skrw 	int i, p1, p2;
12600f1cd5a2Skrw 	char *line = NULL;
12610f1cd5a2Skrw 	size_t linesize = 0;
12620f1cd5a2Skrw 	ssize_t linelen;
12636fe57b42Smillert 
12640f1cd5a2Skrw 	for (;;) {
12650fbd3c97Skrw 		spp = sort_partitions(lp);
12660f1cd5a2Skrw 		for (i = 0; spp[i+1] != NULL; i++) {
1267430e1380Skrw 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) >
12680f1cd5a2Skrw 			    DL_GETPOFFSET(spp[i+1]))
12690f1cd5a2Skrw 				break;
1270616cd1c4Smillert 		}
12710f1cd5a2Skrw 		if (spp[i+1] == NULL) {
12720f1cd5a2Skrw 			free(line);
1273e6aa8bafSmillert 			return (0);
12746fe57b42Smillert 		}
12756fe57b42Smillert 
12760f1cd5a2Skrw 		p1 = 'a' + (spp[i] - lp->d_partitions);
12770f1cd5a2Skrw 		p2 = 'a' + (spp[i+1] - lp->d_partitions);
12780f1cd5a2Skrw 		printf("\nError, partitions %c and %c overlap:\n", p1, p2);
12790f1cd5a2Skrw 		printf("#    %16.16s %16.16s  fstype [fsize bsize    cpg]\n",
12800f1cd5a2Skrw 		    "size", "offset");
12810f1cd5a2Skrw 		display_partition(stdout, lp, p1 - 'a', 0);
12820f1cd5a2Skrw 		display_partition(stdout, lp, p2 - 'a', 0);
12830f1cd5a2Skrw 
12840f1cd5a2Skrw 		for (;;) {
12850f1cd5a2Skrw 			printf("Disable which one? (%c %c) ", p1, p2);
12860f1cd5a2Skrw 			linelen = getline(&line, &linesize, stdin);
12870f1cd5a2Skrw 			if (linelen == -1)
12880f1cd5a2Skrw 				goto done;
12890f1cd5a2Skrw 			if (linelen == 2 && (line[0] == p1 || line[0] == p2))
12900f1cd5a2Skrw 				break;
12910f1cd5a2Skrw 		}
12920f1cd5a2Skrw 		lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED;
12930f1cd5a2Skrw 	}
12940f1cd5a2Skrw 
12950f1cd5a2Skrw done:
12960f1cd5a2Skrw 	putchar('\n');
12970f1cd5a2Skrw 	free(line);
12980f1cd5a2Skrw 	return (1);
12990f1cd5a2Skrw }
13000f1cd5a2Skrw 
13016fe57b42Smillert void
13029fdcb4d6Skrw edit_parms(struct disklabel *lp)
13036fe57b42Smillert {
13046fe57b42Smillert 	char *p;
13059fdcb4d6Skrw 	u_int64_t freesectors, ui;
130696a888c6Smillert 	struct disklabel oldlabel = *lp;
13076fe57b42Smillert 
1308ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
13096fe57b42Smillert 
13100f820bbbSmillert 	/* disk type */
13110f820bbbSmillert 	for (;;) {
1312c33fcabaSmillert 		p = getstring("disk type",
131341282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
131441282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
1315ac30837aSkrw 		if (p == NULL)
131696a888c6Smillert 			return;
131741282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
131841282a2aSmillert 			ui = DTYPE_ESDI;
131941282a2aSmillert 		else
1320c5229dceSkrw 			for (ui = 1; ui < DKMAXTYPES && strcasecmp(p,
1321c5229dceSkrw 			    dktypenames[ui]); ui++)
13220f820bbbSmillert 				;
13230f820bbbSmillert 		if (ui < DKMAXTYPES) {
13240f820bbbSmillert 			break;
13250f820bbbSmillert 		} else {
13260f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13270f820bbbSmillert 			fputs("Valid types are: ", stdout);
13280f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13290f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13300f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13310f820bbbSmillert 					fputs(", ", stdout);
13320f820bbbSmillert 			}
13330f820bbbSmillert 			putchar('\n');
13340f820bbbSmillert 		}
13350f820bbbSmillert 	}
13360f820bbbSmillert 	lp->d_type = ui;
13370f820bbbSmillert 
13386fe57b42Smillert 	/* pack/label id */
1339c33fcabaSmillert 	p = getstring("label name",
13406fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13416fe57b42Smillert 	    lp->d_packname);
134296a888c6Smillert 	if (p == NULL) {
134396a888c6Smillert 		*lp = oldlabel;		/* undo damage */
134496a888c6Smillert 		return;
134596a888c6Smillert 	}
13464fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
13476fe57b42Smillert 
13486fe57b42Smillert 	/* sectors/track */
13496fe57b42Smillert 	for (;;) {
13500db7769aSkrw 		ui = getnumber("sectors/track",
1351cfd24250Skrw 		    "The Number of sectors per track.", lp->d_nsectors,
13520db7769aSkrw 		    UINT32_MAX);
1353aa3970cdSkrw 		if (ui == CMD_ABORTED) {
135496a888c6Smillert 			*lp = oldlabel;		/* undo damage */
135596a888c6Smillert 			return;
1356aa3970cdSkrw 		} else if (ui == CMD_BADVALUE)
1357ac30837aSkrw 			;	/* Try again. */
13586fe57b42Smillert 		else
13596fe57b42Smillert 			break;
13606fe57b42Smillert 	}
13616fe57b42Smillert 	lp->d_nsectors = ui;
13626fe57b42Smillert 
13636fe57b42Smillert 	/* tracks/cylinder */
13646fe57b42Smillert 	for (;;) {
13650db7769aSkrw 		ui = getnumber("tracks/cylinder",
13666fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
13670db7769aSkrw 		    UINT32_MAX);
1368aa3970cdSkrw 		if (ui == CMD_ABORTED) {
136996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
137096a888c6Smillert 			return;
1371aa3970cdSkrw 		} else if (ui == CMD_BADVALUE)
1372ac30837aSkrw 			;	/* Try again. */
13736fe57b42Smillert 		else
13746fe57b42Smillert 			break;
13756fe57b42Smillert 	}
13766fe57b42Smillert 	lp->d_ntracks = ui;
13776fe57b42Smillert 
13786fe57b42Smillert 	/* sectors/cylinder */
1379148b6188Smillert 	for (;;) {
13800db7769aSkrw 		ui = getnumber("sectors/cylinder",
1381148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
13820db7769aSkrw 		    "* tracks/cylinder).", lp->d_secpercyl, UINT32_MAX);
1383aa3970cdSkrw 		if (ui == CMD_ABORTED) {
138496a888c6Smillert 			*lp = oldlabel;		/* undo damage */
138596a888c6Smillert 			return;
1386aa3970cdSkrw 		} else if (ui == CMD_BADVALUE)
1387ac30837aSkrw 			;	/* Try again. */
1388148b6188Smillert 		else
1389148b6188Smillert 			break;
1390148b6188Smillert 	}
1391148b6188Smillert 	lp->d_secpercyl = ui;
13926fe57b42Smillert 
13936fe57b42Smillert 	/* number of cylinders */
13946fe57b42Smillert 	for (;;) {
13950db7769aSkrw 		ui = getnumber("number of cylinders",
13966fe57b42Smillert 		    "The total number of cylinders on the disk.",
13970db7769aSkrw 		    lp->d_ncylinders, UINT32_MAX);
1398aa3970cdSkrw 		if (ui == CMD_ABORTED) {
139996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
140096a888c6Smillert 			return;
1401aa3970cdSkrw 		} else if (ui == CMD_BADVALUE)
1402ac30837aSkrw 			;	/* Try again. */
14036fe57b42Smillert 		else
14046fe57b42Smillert 			break;
14056fe57b42Smillert 	}
14066fe57b42Smillert 	lp->d_ncylinders = ui;
14076fe57b42Smillert 
14086fe57b42Smillert 	/* total sectors */
14096fe57b42Smillert 	for (;;) {
1410b9fc9a72Sderaadt 		u_int64_t nsec = MAXIMUM(DL_GETDSIZE(lp),
141134af67a3Sotto 		    (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
1412117239d3Skrw 		ui = getuint64(lp, "total sectors",
14136fe57b42Smillert 		    "The total number of sectors on the disk.",
141440b226e8Skrw 		    nsec, nsec, NULL);
1415aa3970cdSkrw 		if (ui == CMD_ABORTED) {
141696a888c6Smillert 			*lp = oldlabel;		/* undo damage */
141796a888c6Smillert 			return;
1418aa3970cdSkrw 		} else if (ui == CMD_BADVALUE)
1419ac30837aSkrw 			;	/* Try again. */
14201e0ad43cSotto 		else if (ui > DL_GETDSIZE(lp) &&
14211e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
1422f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1423f98aebd4Smillert 			    "partition.");
14246fe57b42Smillert 			break;
14251e0ad43cSotto 		} else if (ui < DL_GETDSIZE(lp) &&
14261e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
14276fe57b42Smillert 			/* shrink free count */
14289fdcb4d6Skrw 			freesectors = editor_countfree(lp);
14299fdcb4d6Skrw 			if (DL_GETDSIZE(lp) - ui > freesectors)
14306fe57b42Smillert 				fprintf(stderr,
14311e0ad43cSotto 				    "Not enough free space to shrink by %llu "
14321e0ad43cSotto 				    "sectors (only %llu sectors left)\n",
14339fdcb4d6Skrw 				    DL_GETDSIZE(lp) - ui, freesectors);
1434c4f83f03Skrw 			else
14356fe57b42Smillert 				break;
14366fe57b42Smillert 		} else
14376fe57b42Smillert 			break;
14386fe57b42Smillert 	}
143941ed49b7Smillert 	/* Adjust ending_sector if necessary. */
144078f0fb17Skrw 	if (ending_sector > ui) {
144196a888c6Smillert 		ending_sector = ui;
144278f0fb17Skrw 		DL_SETBEND(lp, ending_sector);
144378f0fb17Skrw 	}
14441e0ad43cSotto 	DL_SETDSIZE(lp, ui);
14456fe57b42Smillert }
1446a7e61405Smillert 
1447a7e61405Smillert struct partition **
14480fbd3c97Skrw sort_partitions(struct disklabel *lp)
1449a7e61405Smillert {
1450d18c2a43Skrw 	static struct partition *spp[MAXPARTITIONS+2];
14510fbd3c97Skrw 	int i, npartitions;
1452a7e61405Smillert 
1453d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1454d18c2a43Skrw 
1455a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1456a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
14571e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1458a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1459a7e61405Smillert 	}
1460a7e61405Smillert 
1461a7e61405Smillert 	/*
1462a7e61405Smillert 	 * Sort the partitions based on starting offset.
1463a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1464a7e61405Smillert 	 */
1465a7e61405Smillert 	if (npartitions > 1)
14660f1cd5a2Skrw 		if (mergesort((void *)spp, npartitions, sizeof(spp[0]),
1467a7e61405Smillert 		    partition_cmp))
1468a7e61405Smillert 			err(4, "failed to sort partition table");
1469a7e61405Smillert 
1470a7e61405Smillert 	return (spp);
1471a7e61405Smillert }
14720f820bbbSmillert 
14730f820bbbSmillert /*
14740f820bbbSmillert  * Get a valid disk type if necessary.
14750f820bbbSmillert  */
14760f820bbbSmillert void
14778809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev)
14780f820bbbSmillert {
14790f820bbbSmillert 	int i;
1480b228e876Smiod 	char *s;
1481b228e876Smiod 	const char *def = "SCSI";
1482b228e876Smiod 	const struct dtypes {
1483b228e876Smiod 		const char *dev;
1484b228e876Smiod 		const char *type;
1485803ff7d5Smillert 	} dtypes[] = {
1486c33fcabaSmillert 		{ "sd",   "SCSI" },
1487c33fcabaSmillert 		{ "wd",   "IDE" },
1488c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1489c33fcabaSmillert 		{ "xd",   "SMD" },
1490c33fcabaSmillert 		{ "xy",   "SMD" },
1491c33fcabaSmillert 		{ "hd",   "HP-IB" },
1492c33fcabaSmillert 		{ "vnd",  "VND" },
1493c33fcabaSmillert 		{ "svnd", "VND" },
1494c33fcabaSmillert 		{ NULL,   NULL }
1495803ff7d5Smillert 	};
1496803ff7d5Smillert 
1497803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1498803ff7d5Smillert 		if (*s == 'r')
1499803ff7d5Smillert 			s++;
1500803ff7d5Smillert 		i = strcspn(s, "0123456789");
1501803ff7d5Smillert 		s[i] = '\0';
1502803ff7d5Smillert 		dev = s;
1503803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1504803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1505803ff7d5Smillert 				def = dtypes[i].type;
1506803ff7d5Smillert 				break;
1507803ff7d5Smillert 			}
1508803ff7d5Smillert 		}
1509803ff7d5Smillert 	}
15100f820bbbSmillert 
15110f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15120f820bbbSmillert 		puts(banner);
15130f820bbbSmillert 		puts("Possible values are:");
1514eb5dd924Sderaadt 		printf("\"IDE\", ");
15150f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15160f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15170f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15180f820bbbSmillert 				fputs(", ", stdout);
15190f820bbbSmillert 		}
15200f820bbbSmillert 		putchar('\n');
15210f820bbbSmillert 
15220f820bbbSmillert 		for (;;) {
1523c33fcabaSmillert 			s = getstring("Disk type",
1524803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1525d7878011Sderaadt 			    "ESDI, ST506, or floppy.", def);
152696a888c6Smillert 			if (s == NULL)
152796a888c6Smillert 				continue;
15285b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15295b412421Smillert 				lp->d_type = DTYPE_ESDI;
15305b412421Smillert 				return;
15315b412421Smillert 			}
15320f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15330f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15340f820bbbSmillert 					lp->d_type = i;
15350f820bbbSmillert 					return;
15360f820bbbSmillert 				}
15370f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15380f820bbbSmillert 			fputs("Valid types are: ", stdout);
15390f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15400f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15410f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15420f820bbbSmillert 					fputs(", ", stdout);
15430f820bbbSmillert 			}
15440f820bbbSmillert 			putchar('\n');
15450f820bbbSmillert 		}
15460f820bbbSmillert 	}
15470f820bbbSmillert }
154896a888c6Smillert 
154996a888c6Smillert /*
155096a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
155196a888c6Smillert  * from the user.
155296a888c6Smillert  */
155396a888c6Smillert void
15549fdcb4d6Skrw set_bounds(struct disklabel *lp)
155596a888c6Smillert {
15561e0ad43cSotto 	u_int64_t ui, start_temp;
155796a888c6Smillert 
155896a888c6Smillert 	/* Starting sector */
1559f1bc1b27Skrw 	for (;;) {
1560117239d3Skrw 		ui = getuint64(lp, "Starting sector",
156196a888c6Smillert 		    "The start of the OpenBSD portion of the disk.",
156240b226e8Skrw 		    starting_sector, DL_GETDSIZE(lp), NULL);
1563aa3970cdSkrw 		if (ui == CMD_ABORTED)
156496a888c6Smillert 			return;
1565aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1566f1bc1b27Skrw 			;	/* Try again. */
1567f1bc1b27Skrw 		else if (ui >= DL_GETDSIZE(lp))
1568f1bc1b27Skrw 			fprintf(stderr, "starting sector must be < %llu\n",
1569f1bc1b27Skrw 			    DL_GETDSIZE(lp));
1570f1bc1b27Skrw 		else
1571f1bc1b27Skrw 			break;
1572f1bc1b27Skrw 	}
157396a888c6Smillert 	start_temp = ui;
157496a888c6Smillert 
15754793b14cSmillert 	/* Size */
1576f1bc1b27Skrw 	for (;;) {
1577117239d3Skrw 		ui = getuint64(lp, "Size ('*' for entire disk)",
1578f98aebd4Smillert 		    "The size of the OpenBSD portion of the disk ('*' for the "
1579f98aebd4Smillert 		    "entire disk).", ending_sector - starting_sector,
158040b226e8Skrw 		    DL_GETDSIZE(lp) - start_temp, NULL);
1581aa3970cdSkrw 		if (ui == CMD_ABORTED)
158296a888c6Smillert 			return;
1583aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1584f1bc1b27Skrw 			;	/* Try again. */
1585f1bc1b27Skrw 		else if (ui > DL_GETDSIZE(lp) - start_temp)
1586f1bc1b27Skrw 			fprintf(stderr, "size must be <= %llu\n",
1587f1bc1b27Skrw 			    DL_GETDSIZE(lp) - start_temp);
1588f1bc1b27Skrw 		else
1589f1bc1b27Skrw 			break;
1590f1bc1b27Skrw 	}
15914793b14cSmillert 	ending_sector = start_temp + ui;
159278f0fb17Skrw 	DL_SETBEND(lp, ending_sector);
159396a888c6Smillert 	starting_sector = start_temp;
159478f0fb17Skrw 	DL_SETBSTART(lp, starting_sector);
159596a888c6Smillert }
159696a888c6Smillert 
159796a888c6Smillert /*
15980d63cfbaSjsing  * Allow user to interactively change disklabel UID.
15990d63cfbaSjsing  */
16000d63cfbaSjsing void
160169a6ffbcSjsing set_duid(struct disklabel *lp)
16020d63cfbaSjsing {
16030d63cfbaSjsing 	char *s;
16040d63cfbaSjsing 	int i;
16050d63cfbaSjsing 
1606f6ad9e2dSjsing 	printf("The disklabel UID is currently: "
1607f6ad9e2dSjsing 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
1608f6ad9e2dSjsing 	    lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
1609f6ad9e2dSjsing 	    lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
16100d63cfbaSjsing 
16110d63cfbaSjsing 	do {
161269a6ffbcSjsing 		s = getstring("duid", "The disklabel UID, given as a 16 "
16130d63cfbaSjsing 		    "character hexadecimal string.", NULL);
1614ce98d1aeShalex 		if (s == NULL || strlen(s) == 0) {
16150d63cfbaSjsing 			fputs("Command aborted\n", stderr);
16160d63cfbaSjsing 			return;
16170d63cfbaSjsing 		}
161869a6ffbcSjsing 		i = duid_parse(lp, s);
16190d63cfbaSjsing 		if (i != 0)
16200d63cfbaSjsing 			fputs("Invalid UID entered.\n", stderr);
16210d63cfbaSjsing 	} while (i != 0);
16220d63cfbaSjsing }
16230d63cfbaSjsing 
16240d63cfbaSjsing /*
162596a888c6Smillert  * Return a list of the "chunks" of free space available
162696a888c6Smillert  */
162796a888c6Smillert struct diskchunk *
16288809fabbSderaadt free_chunks(struct disklabel *lp)
162996a888c6Smillert {
163096a888c6Smillert 	struct partition **spp;
163196a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
163299bd27d2Skrw 	u_int64_t start, stop;
163396a888c6Smillert 	int i, numchunks;
163496a888c6Smillert 
16350fbd3c97Skrw 	/* Sort the in-use partitions based on offset */
16360fbd3c97Skrw 	spp = sort_partitions(lp);
163796a888c6Smillert 
163896a888c6Smillert 	/* If there are no partitions, it's all free. */
16390fbd3c97Skrw 	if (spp[0] == NULL) {
16402d8451b0Smillert 		chunks[0].start = starting_sector;
164196a888c6Smillert 		chunks[0].stop = ending_sector;
164296a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
164396a888c6Smillert 		return (chunks);
164496a888c6Smillert 	}
164596a888c6Smillert 
164696a888c6Smillert 	/* Find chunks of free space */
164796a888c6Smillert 	numchunks = 0;
16480fbd3c97Skrw 	if (DL_GETPOFFSET(spp[0]) > starting_sector) {
16492d8451b0Smillert 		chunks[0].start = starting_sector;
16501e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
165196a888c6Smillert 		numchunks++;
165296a888c6Smillert 	}
16530fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
165499bd27d2Skrw 		start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1655aff3f969Sotto 		if (start < starting_sector)
1656aff3f969Sotto 			start = starting_sector;
1657aff3f969Sotto 		else if (start > ending_sector)
1658aff3f969Sotto 			start = ending_sector;
165999bd27d2Skrw 		if (spp[i + 1] != NULL)
166099bd27d2Skrw 			stop = DL_GETPOFFSET(spp[i+1]);
166199bd27d2Skrw 		else
166299bd27d2Skrw 			stop = ending_sector;
1663aff3f969Sotto 		if (stop < starting_sector)
1664aff3f969Sotto 			stop = starting_sector;
1665aff3f969Sotto 		else if (stop > ending_sector)
1666aff3f969Sotto 			stop = ending_sector;
166799bd27d2Skrw 		if (start < stop) {
166899bd27d2Skrw 			chunks[numchunks].start = start;
166999bd27d2Skrw 			chunks[numchunks].stop = stop;
167096a888c6Smillert 			numchunks++;
167196a888c6Smillert 		}
167296a888c6Smillert 	}
167396a888c6Smillert 
167496a888c6Smillert 	/* Terminate and return */
167596a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
167696a888c6Smillert 	return (chunks);
167796a888c6Smillert }
16784793b14cSmillert 
16794793b14cSmillert void
168087023ed9Skrw find_bounds(struct disklabel *lp)
16814793b14cSmillert {
16826534e983Sderaadt 	starting_sector = DL_GETBSTART(lp);
16836534e983Sderaadt 	ending_sector = DL_GETBEND(lp);
1684b2d4a455Smiod 
16856534e983Sderaadt 	if (ending_sector) {
168634ae4198Skrw 		if (verbose)
168734ae4198Skrw 			printf("Treating sectors %llu-%llu as the OpenBSD"
168834ae4198Skrw 			    " portion of the disk.\nYou can use the 'b'"
168934ae4198Skrw 			    " command to change this.\n\n", starting_sector,
169034ae4198Skrw 			    ending_sector);
16914793b14cSmillert 	}
1692b2d4a455Smiod }
1693c0bdc608Smillert 
1694c0bdc608Smillert /*
1695c0bdc608Smillert  * Calculate free space.
1696c0bdc608Smillert  */
16979fdcb4d6Skrw u_int64_t
16989fdcb4d6Skrw editor_countfree(struct disklabel *lp)
1699c0bdc608Smillert {
1700d93cb2bbSkrw 	struct diskchunk *chunks;
17019fdcb4d6Skrw 	u_int64_t freesectors = 0;
1702c0bdc608Smillert 	int i;
1703c0bdc608Smillert 
1704d93cb2bbSkrw 	chunks = free_chunks(lp);
1705509930fbSotto 
1706d93cb2bbSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++)
17079fdcb4d6Skrw 		freesectors += chunks[i].stop - chunks[i].start;
17089fdcb4d6Skrw 
17099fdcb4d6Skrw 	return (freesectors);
1710c0bdc608Smillert }
1711617e6e4aSmillert 
1712617e6e4aSmillert void
17134d812bb6Slum editor_help(void)
1714617e6e4aSmillert {
1715617e6e4aSmillert 	puts("Available commands:");
1716617e6e4aSmillert 	puts(
17174d812bb6Slum " ? | h    - show help                 n [part] - set mount point\n"
171849159a67Skrw " A        - auto partition all space  p [unit] - print partitions\n"
171949159a67Skrw " a [part] - add partition             q        - quit & save changes\n"
17204659aa0dSotto " b        - set OpenBSD boundaries    R [part] - resize auto allocated partition\n"
172149159a67Skrw " c [part] - change partition size     r        - display free space\n"
17226aaa4aabSotto " D        - reset label to default    s [path] - save label to file\n"
17236aaa4aabSotto " d [part] - delete partition          U        - undo all changes\n"
17246aaa4aabSotto " e        - edit drive parameters     u        - undo last change\n"
17256aaa4aabSotto " g [d|u]  - [d]isk or [u]ser geometry w        - write label to disk\n"
17260d63cfbaSjsing " i        - modify disklabel UID      X        - toggle expert mode\n"
17270d63cfbaSjsing " l [unit] - print disk label header   x        - exit & lose changes\n"
17280d63cfbaSjsing " M        - disklabel(8) man page     z        - delete all partitions\n"
17290d63cfbaSjsing " m [part] - modify partition\n"
1730c4884206Skrw "\n"
1731c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1732e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n"
1733e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1734c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
17354d812bb6Slum 
1736617e6e4aSmillert }
1737bd6726faSmillert 
17384f3bbbf0Skrw void
17398809fabbSderaadt mpcopy(char **to, char **from)
1740bd6726faSmillert {
1741bd6726faSmillert 	int i;
1742bd6726faSmillert 
1743bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1744bd6726faSmillert 		free(to[i]);
1745bd6726faSmillert 		to[i] = NULL;
1746408ab9bcSkrw 		if (from[i] != NULL) {
1747408ab9bcSkrw 			to[i] = strdup(from[i]);
1748408ab9bcSkrw 			if (to[i] == NULL)
1749408ab9bcSkrw 				errx(4, "out of memory");
1750bd6726faSmillert 		}
1751bd6726faSmillert 	}
1752bd6726faSmillert }
1753bd6726faSmillert 
1754bd6726faSmillert int
17558809fabbSderaadt mpequal(char **mp1, char **mp2)
1756bd6726faSmillert {
1757bd6726faSmillert 	int i;
1758bd6726faSmillert 
1759bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1760bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1761bd6726faSmillert 			continue;
1762bd6726faSmillert 
1763bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1764bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1765bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1766bd6726faSmillert 			return (0);
1767bd6726faSmillert 	}
1768bd6726faSmillert 	return (1);
1769bd6726faSmillert }
1770bd6726faSmillert 
177193160b9bSkrw void
177234ae4198Skrw mpsave(struct disklabel *lp)
1773bd6726faSmillert {
1774d8b446ceSderaadt 	int i, j;
1775b9fc9a72Sderaadt 	char bdev[PATH_MAX], *p;
17763f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1777bd6726faSmillert 	FILE *fp;
1778fe01da94Skrw 	u_int8_t fstype;
1779bd6726faSmillert 
178093160b9bSkrw 	if (!fstabfile)
178193160b9bSkrw 		return;
178293160b9bSkrw 
17833f843443Smillert 	memset(&mi, 0, sizeof(mi));
17843f843443Smillert 
1785d8b446ceSderaadt 	for (i = 0; i < MAXPARTITIONS; i++) {
1786fe01da94Skrw 		fstype = lp->d_partitions[i].p_fstype;
1787fe01da94Skrw 		if (mountpoints[i] != NULL || fstype == FS_SWAP) {
178834ae4198Skrw 			mi[i].mountpoint = mountpoints[i];
17893f843443Smillert 			mi[i].partno = i;
1790bd6726faSmillert 		}
1791bd6726faSmillert 	}
1792bd6726faSmillert 
179334ae4198Skrw 	/* Convert specname to bdev */
1794d6d80bb0Skrw 	if (uidflag) {
1795d6d80bb0Skrw 		snprintf(bdev, sizeof(bdev),
1796d6d80bb0Skrw 		    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
1797d6d80bb0Skrw 		    lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3],
1798d6d80bb0Skrw 		    lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7],
1799d6d80bb0Skrw 		    specname[strlen(specname)-1]);
1800d6d80bb0Skrw 	} else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
180134ae4198Skrw 	    specname[sizeof(_PATH_DEV) - 1] == 'r') {
1802bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
180334ae4198Skrw 		    &specname[sizeof(_PATH_DEV)]);
1804bd6726faSmillert 	} else {
180534ae4198Skrw 		if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
180693160b9bSkrw 			return;
1807bd6726faSmillert 		*p = '\0';
180834ae4198Skrw 		snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1809bd6726faSmillert 		*p = 'r';
1810bd6726faSmillert 	}
1811bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1812bd6726faSmillert 
18133f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
18143f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
18153f843443Smillert 
1816d71533c9Stedu 	if ((fp = fopen(fstabfile, "w"))) {
1817fe01da94Skrw 		for (i = 0; i < MAXPARTITIONS; i++) {
18185fea0b85Smillert 			j =  mi[i].partno;
1819fe01da94Skrw 			fstype = lp->d_partitions[j].p_fstype;
1820fe01da94Skrw 			if (fstype == FS_SWAP) {
1821fe01da94Skrw 				fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j);
1822fe01da94Skrw 			} else if (mi[i].mountpoint) {
1823fe01da94Skrw 				fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev,
1824fe01da94Skrw 				    'a' + j, mi[i].mountpoint,
1825fe01da94Skrw 				    fstypesnames[fstype], j == 0 ? 1 : 2);
1826fe01da94Skrw 			}
1827bd6726faSmillert 		}
1828bd6726faSmillert 		fclose(fp);
182993160b9bSkrw 	}
1830bd6726faSmillert }
183124a2c1a4Smillert 
1832408ab9bcSkrw void
1833408ab9bcSkrw mpfree(char **mp)
1834408ab9bcSkrw {
1835408ab9bcSkrw 	int part;
1836408ab9bcSkrw 
1837408ab9bcSkrw 	if (mp == NULL)
1838408ab9bcSkrw 		return;
1839408ab9bcSkrw 
184075691760Skrw 	for (part = 0; part < MAXPARTITIONS; part++)
1841408ab9bcSkrw 		free(mp[part]);
1842408ab9bcSkrw 
1843408ab9bcSkrw 	free(mp);
1844408ab9bcSkrw }
1845408ab9bcSkrw 
184624a2c1a4Smillert int
1847604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
184824a2c1a4Smillert {
184940b226e8Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
185040b226e8Skrw 	u_int64_t ui, offsetalign;
185140b226e8Skrw 	int flags;
185224a2c1a4Smillert 
185340b226e8Skrw 	flags = DO_CONVERSIONS;
1854117239d3Skrw 	ui = getuint64(lp, "offset",
18551e0ad43cSotto 	    "Starting sector for this partition.",
18561e0ad43cSotto 	    DL_GETPOFFSET(pp),
185740b226e8Skrw 	    DL_GETPOFFSET(pp), &flags);
1858e9ff19beSkrw 
185940b226e8Skrw 	if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
186040b226e8Skrw 		return (1);
1861fc1a4cc6Sderaadt #ifdef SUN_AAT0
186240b226e8Skrw 	if (partno == 0 && ui != 0) {
186349bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
186440f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
186540b226e8Skrw 		return (1);
186624a2c1a4Smillert 	}
186740b226e8Skrw #endif
186840b226e8Skrw 	opp = *pp;
186940b226e8Skrw 	DL_SETPOFFSET(pp, ui);
187040b226e8Skrw 	offsetalign = 1;
187140b226e8Skrw 	if ((flags & DO_ROUNDING) != 0 && pp->p_fstype == FS_BSDFFS)
187240b226e8Skrw 		offsetalign = lp->d_secpercyl;
187340b226e8Skrw 
187440b226e8Skrw 	if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP) == 1) {
187540b226e8Skrw 		*pp = opp;
187640b226e8Skrw 		return (1);
187715c15d8aSkrw 	}
1878e9ff19beSkrw 
187940b226e8Skrw 	if (expert == 1 && quiet == 0 && ui != DL_GETPOFFSET(pp))
188040b226e8Skrw 		printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp));
188140b226e8Skrw 
188240b226e8Skrw 	return (0);
188315c15d8aSkrw }
188424a2c1a4Smillert 
188524a2c1a4Smillert int
18869fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
188724a2c1a4Smillert {
188840b226e8Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
188940b226e8Skrw 	u_int64_t maxsize, ui, sizealign;
189040b226e8Skrw 	int flags;
189114192793Skrw 
189214192793Skrw 	maxsize = max_partition_size(lp, partno);
189340b226e8Skrw 	flags = DO_CONVERSIONS;
1894117239d3Skrw 	ui = getuint64(lp, "size", "Size of the partition. "
18957da73705Skrw 	    "You may also say +/- amount for a relative change.",
189640b226e8Skrw 	    DL_GETPSIZE(pp), maxsize, &flags);
1897e9ff19beSkrw 
189840b226e8Skrw 	if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
189940b226e8Skrw 		return (1);
190040b226e8Skrw 
190140b226e8Skrw 	opp = *pp;
190259ccf790Skrw 	DL_SETPSIZE(pp, ui);
190340b226e8Skrw 	sizealign = 1;
190440b226e8Skrw 	if ((flags & DO_ROUNDING) != 0 && (pp->p_fstype == FS_SWAP ||
190540b226e8Skrw 	    pp->p_fstype == FS_BSDFFS))
190640b226e8Skrw 		sizealign = lp->d_secpercyl;
190740b226e8Skrw 
190840b226e8Skrw 	if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP) == 1) {
190940b226e8Skrw 		*pp = opp;
191040b226e8Skrw 		return (1);
191124a2c1a4Smillert 	}
1912e9ff19beSkrw 
191340b226e8Skrw 	if (expert == 1 && quiet == 0 && ui != DL_GETPSIZE(pp))
191440b226e8Skrw 		printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp));
191540b226e8Skrw 
191640b226e8Skrw 	return (0);
1917e9ff19beSkrw }
191824a2c1a4Smillert 
191924a2c1a4Smillert int
1920a95dd767Sotto get_cpg(struct disklabel *lp, int partno)
1921a95dd767Sotto {
1922a95dd767Sotto 	u_int64_t ui;
1923a95dd767Sotto 	struct partition *pp = &lp->d_partitions[partno];
1924a95dd767Sotto 
19254aa85578Skrw 	if (pp->p_fstype != FS_BSDFFS)
19264aa85578Skrw 		return (0);
19274aa85578Skrw 
19284aa85578Skrw 	if (pp->p_cpg == 0)
19294aa85578Skrw 		pp->p_cpg = 1;
19304aa85578Skrw 
193140b226e8Skrw 	if (expert == 0)
1932a95dd767Sotto 		return (0);
1933a95dd767Sotto 
1934a95dd767Sotto 	for (;;) {
19350db7769aSkrw 		ui = getnumber("cpg", "Size of partition in fs blocks.",
19360db7769aSkrw 		    pp->p_cpg, USHRT_MAX);
1937aa3970cdSkrw 		if (ui == CMD_ABORTED)
1938a95dd767Sotto 			return (1);
1939aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1940ac30837aSkrw 			;	/* Try again. */
1941ac30837aSkrw 		else
1942a95dd767Sotto 			break;
1943a95dd767Sotto 	}
1944a95dd767Sotto 	pp->p_cpg = ui;
1945a95dd767Sotto 	return (0);
1946a95dd767Sotto }
1947a95dd767Sotto 
1948a95dd767Sotto int
19498809fabbSderaadt get_fsize(struct disklabel *lp, int partno)
195024a2c1a4Smillert {
195124a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
1952a3ad4147Skrw 	u_int64_t ui, bytes;
1953a3ad4147Skrw 	u_int32_t frag, fsize;
195424a2c1a4Smillert 
1955a3ad4147Skrw 	if (pp->p_fstype != FS_BSDFFS)
1956a4c87e64Skrw 		return (0);
1957a4c87e64Skrw 
1958ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1959ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1960a3ad4147Skrw 	if (fsize == 0) {
1961a3ad4147Skrw 		fsize = 2048;
1962ddfcbf38Sotto 		frag = 8;
1963a3ad4147Skrw 		bytes = DL_GETPSIZE(pp) * lp->d_secsize;
1964a3ad4147Skrw 		if (bytes > 128ULL * 1024 * 1024 * 1024)
1965a3ad4147Skrw 			fsize *= 2;
1966a3ad4147Skrw 		if (bytes > 512ULL * 1024 * 1024 * 1024)
1967a3ad4147Skrw 			fsize *= 2;
1968a3ad4147Skrw 		if (fsize < lp->d_secsize)
1969a3ad4147Skrw 			fsize = lp->d_secsize;
1970a3ad4147Skrw 		if (fsize > MAXBSIZE / frag)
1971a3ad4147Skrw 			fsize = MAXBSIZE / frag;
1972a3ad4147Skrw 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag);
1973a3ad4147Skrw 	}
1974a3ad4147Skrw 
1975a3ad4147Skrw 	if (expert == 0)
1976a3ad4147Skrw 		return (0);
1977ddfcbf38Sotto 
197824a2c1a4Smillert 	for (;;) {
19790db7769aSkrw 		ui = getnumber("fragment size",
1980c782b064Skrw 		    "Size of ffs block fragments. A multiple of the disk "
19810db7769aSkrw 		    "sector-size.", fsize, UINT32_MAX);
1982aa3970cdSkrw 		if (ui == CMD_ABORTED)
198324a2c1a4Smillert 			return (1);
1984aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1985ac30837aSkrw 			;	/* Try again. */
1986ac30837aSkrw 		else if (ui < lp->d_secsize || (ui % lp->d_secsize) != 0)
1987c782b064Skrw 			fprintf(stderr, "Error: fragment size must be a "
1988c782b064Skrw 			    "multiple of the disk sector size (%d)\n",
1989c782b064Skrw 			    lp->d_secsize);
1990ac30837aSkrw 		else
199124a2c1a4Smillert 			break;
199224a2c1a4Smillert 	}
199324a2c1a4Smillert 	if (ui == 0)
199424a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
1995ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag);
199624a2c1a4Smillert 	return (0);
199724a2c1a4Smillert }
199824a2c1a4Smillert 
199924a2c1a4Smillert int
20008809fabbSderaadt get_bsize(struct disklabel *lp, int partno)
200124a2c1a4Smillert {
20027a687b60Skrw 	u_int64_t ui, frag, fsize;
200340b226e8Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
200440b226e8Skrw 	u_int64_t offsetalign, sizealign;
20056be94867Skrw 	char *p;
200624a2c1a4Smillert 
2007a49bdda8Skrw 	if (pp->p_fstype != FS_BSDFFS)
2008a4c87e64Skrw 		return (0);
2009a4c87e64Skrw 
201024a2c1a4Smillert 	/* Avoid dividing by zero... */
2011ddfcbf38Sotto 	if (pp->p_fragblock == 0)
201224a2c1a4Smillert 		return (1);
2013ddfcbf38Sotto 
201440b226e8Skrw 	opp = *pp;
201540b226e8Skrw 	if (expert == 0)
2016a49bdda8Skrw 		goto align;
2017a49bdda8Skrw 
2018ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
2019ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
202024a2c1a4Smillert 
202124a2c1a4Smillert 	for (;;) {
20220db7769aSkrw 		ui = getnumber("block size",
20230cf7e76dSotto 		    "Size of ffs blocks. 1, 2, 4 or 8 times ffs fragment size.",
20240db7769aSkrw 		    fsize * frag, UINT32_MAX);
202524a2c1a4Smillert 
202624a2c1a4Smillert 		/* sanity checks */
2027aa3970cdSkrw 		if (ui == CMD_ABORTED)
202824a2c1a4Smillert 			return (1);
2029aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
2030ac30837aSkrw 			;	/* Try again. */
203124a2c1a4Smillert 		else if (ui < getpagesize())
203224a2c1a4Smillert 			fprintf(stderr,
203324a2c1a4Smillert 			    "Error: block size must be at least as big "
203424a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
20350cf7e76dSotto 		else if (ui < fsize || (fsize != ui && fsize * 2 != ui &&
20360cf7e76dSotto 		    fsize * 4 != ui && fsize * 8 != ui))
20370cf7e76dSotto 			fprintf(stderr, "Error: block size must be 1, 2, 4 or "
20380cf7e76dSotto 			    "8 times fragment size (%llu).\n",
20392777acfaSchl 			    (unsigned long long) fsize);
204024a2c1a4Smillert 		else
204124a2c1a4Smillert 			break;
204224a2c1a4Smillert 	}
20430cf7e76dSotto 	frag = ui / fsize;
20440cf7e76dSotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag);
2045a49bdda8Skrw 
204640b226e8Skrw #ifdef SUN_CYLCHECK
20476be94867Skrw 	return (0);
20486be94867Skrw #endif
204940b226e8Skrw 	p = getstring("Align partition to block size",
205040b226e8Skrw 	    "Round the partition offset and size to multiples of bsize?", "y");
205140b226e8Skrw 	if (*p == 'n' || *p == 'N')
205240b226e8Skrw 		return (0);
20536be94867Skrw 
20546be94867Skrw align:
205540b226e8Skrw #ifdef SUN_CYLCHECK
205640b226e8Skrw 	return (0);
2057a49bdda8Skrw #endif
205840b226e8Skrw 	sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) *
205940b226e8Skrw 	    DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize;
206040b226e8Skrw 	offsetalign = 1;
206140b226e8Skrw 	if (DL_GETPOFFSET(pp) != starting_sector)
206240b226e8Skrw 		offsetalign = sizealign;
206340b226e8Skrw 
2064922b28b8Skrw 	if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP |
2065922b28b8Skrw 	    ROUND_SIZE_DOWN | ROUND_SIZE_OVERLAP) == 1) {
206640b226e8Skrw 		*pp = opp;
206740b226e8Skrw 		return (1);
206840b226e8Skrw 	}
206940b226e8Skrw 
207040b226e8Skrw 	if (expert == 1 && quiet == 0 &&
207140b226e8Skrw 	    DL_GETPOFFSET(&opp) != DL_GETPOFFSET(pp))
207240b226e8Skrw 		printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp));
207340b226e8Skrw 	if (expert == 1 && quiet == 0 && DL_GETPSIZE(&opp) != DL_GETPSIZE(pp))
207440b226e8Skrw 		printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp));
207540b226e8Skrw 
207624a2c1a4Smillert 	return (0);
207724a2c1a4Smillert }
207824a2c1a4Smillert 
207924a2c1a4Smillert int
20808809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
208124a2c1a4Smillert {
208224a2c1a4Smillert 	char *p;
20831e0ad43cSotto 	u_int64_t ui;
208424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
208524a2c1a4Smillert 
208624a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
2087c33fcabaSmillert 		p = getstring("FS type",
208824a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
208924a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
209024a2c1a4Smillert 		if (p == NULL) {
209124a2c1a4Smillert 			return (1);
209224a2c1a4Smillert 		}
209324a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
209424a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
209524a2c1a4Smillert 				pp->p_fstype = ui;
209624a2c1a4Smillert 				break;
209724a2c1a4Smillert 			}
209824a2c1a4Smillert 		}
209924a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
2100430e1380Skrw 			printf("Unrecognized filesystem type '%s', treating "
2101430e1380Skrw 			    "as 'unknown'\n", p);
210224a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
210324a2c1a4Smillert 		}
210424a2c1a4Smillert 	} else {
210524a2c1a4Smillert 		for (;;) {
21060db7769aSkrw 			ui = getnumber("FS type (decimal)",
2107430e1380Skrw 			    "Filesystem type as a decimal number; usually 7 "
2108430e1380Skrw 			    "(4.2BSD) or 1 (swap).",
21090db7769aSkrw 			    pp->p_fstype, UINT8_MAX);
2110aa3970cdSkrw 			if (ui == CMD_ABORTED)
211124a2c1a4Smillert 				return (1);
2112aa3970cdSkrw 			else if (ui == CMD_BADVALUE)
2113ac30837aSkrw 				;	/* Try again. */
211424a2c1a4Smillert 			else
211524a2c1a4Smillert 				break;
211624a2c1a4Smillert 		}
211724a2c1a4Smillert 		pp->p_fstype = ui;
211824a2c1a4Smillert 	}
211924a2c1a4Smillert 	return (0);
212024a2c1a4Smillert }
212124a2c1a4Smillert 
212224a2c1a4Smillert int
212334ae4198Skrw get_mp(struct disklabel *lp, int partno)
212424a2c1a4Smillert {
212524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
2126ec9fde5fSkrw 	char *p;
2127ec9fde5fSkrw 	int i;
212824a2c1a4Smillert 
2129b308f3d4Skrw 	if (fstabfile == NULL ||
2130b308f3d4Skrw 	    pp->p_fstype == FS_UNUSED ||
2131b308f3d4Skrw 	    pp->p_fstype == FS_SWAP ||
2132b308f3d4Skrw 	    pp->p_fstype == FS_BOOT ||
2133b308f3d4Skrw 	    pp->p_fstype == FS_OTHER ||
2134b308f3d4Skrw 	    pp->p_fstype == FS_RAID) {
2135b308f3d4Skrw 		/* No fstabfile, no names. Not all fstypes can be named */
2136b308f3d4Skrw 		return 0;
2137b308f3d4Skrw 	}
2138b308f3d4Skrw 
2139ddaff619Smillert 	for (;;) {
2140c33fcabaSmillert 		p = getstring("mount point",
214124a2c1a4Smillert 		    "Where to mount this filesystem (ie: / /var /usr)",
214234ae4198Skrw 		    mountpoints[partno] ? mountpoints[partno] : "none");
2143ac30837aSkrw 		if (p == NULL)
214424a2c1a4Smillert 			return (1);
2145ddaff619Smillert 		if (strcasecmp(p, "none") == 0) {
214634ae4198Skrw 			free(mountpoints[partno]);
214734ae4198Skrw 			mountpoints[partno] = NULL;
2148ddaff619Smillert 			break;
2149ddaff619Smillert 		}
2150ec9fde5fSkrw 		for (i = 0; i < MAXPARTITIONS; i++)
215193160b9bSkrw 			if (mountpoints[i] != NULL && i != partno &&
2152ec9fde5fSkrw 			    strcmp(p, mountpoints[i]) == 0)
2153ec9fde5fSkrw 				break;
2154ec9fde5fSkrw 		if (i < MAXPARTITIONS) {
215593160b9bSkrw 			fprintf(stderr, "'%c' already being mounted at "
215693160b9bSkrw 			    "'%s'\n", 'a'+i, p);
2157ec9fde5fSkrw 			break;
2158ec9fde5fSkrw 		}
2159ddaff619Smillert 		if (*p == '/') {
2160ddaff619Smillert 			/* XXX - might as well realloc */
216134ae4198Skrw 			free(mountpoints[partno]);
216234ae4198Skrw 			if ((mountpoints[partno] = strdup(p)) == NULL)
216324a2c1a4Smillert 				errx(4, "out of memory");
2164ddaff619Smillert 			break;
2165ddaff619Smillert 		}
2166ddaff619Smillert 		fputs("Mount points must start with '/'\n", stderr);
216724a2c1a4Smillert 	}
2168b308f3d4Skrw 
216924a2c1a4Smillert 	return (0);
217024a2c1a4Smillert }
21713f843443Smillert 
21723f843443Smillert int
21738809fabbSderaadt micmp(const void *a1, const void *a2)
21743f843443Smillert {
21753f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
21763f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
21773f843443Smillert 
21783f843443Smillert 	/* We want all the NULLs at the end... */
21793f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
21803f843443Smillert 		return (0);
21813f843443Smillert 	else if (mi1->mountpoint == NULL)
21823f843443Smillert 		return (1);
21833f843443Smillert 	else if (mi2->mountpoint == NULL)
21843f843443Smillert 		return (-1);
21853f843443Smillert 	else
21863f843443Smillert 		return (strcmp(mi1->mountpoint, mi2->mountpoint));
21873f843443Smillert }
2188c33fcabaSmillert 
2189c33fcabaSmillert void
219087023ed9Skrw get_geometry(int f, struct disklabel **dgpp)
2191c33fcabaSmillert {
2192c33fcabaSmillert 	struct stat st;
2193c33fcabaSmillert 	struct disklabel *disk_geop;
219487023ed9Skrw 
2195c33fcabaSmillert 	if (fstat(f, &st) == -1)
2196c33fcabaSmillert 		err(4, "Can't stat device");
2197c33fcabaSmillert 
2198c33fcabaSmillert 	/* Get disk geometry */
2199c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2200c33fcabaSmillert 		errx(4, "out of memory");
220190b0764fSkrw 	if (ioctl(f, DIOCGPDINFO, disk_geop) == -1)
220290b0764fSkrw 		err(4, "DIOCGPDINFO");
2203c33fcabaSmillert 	*dgpp = disk_geop;
2204c33fcabaSmillert }
2205c33fcabaSmillert 
2206c33fcabaSmillert void
22078809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp,
220887023ed9Skrw     struct disklabel *ugp, char *p)
2209c33fcabaSmillert {
2210ac30837aSkrw 	if (p == NULL)
22119a36aa41Ssthen 		p = getstring("[d]isk or [u]ser geometry",
2212c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
22139a36aa41Ssthen 		    "itself thinks it is, or 'u' to use the geometry that "
22149a36aa41Ssthen 		    "was found in the label.",
2215c33fcabaSmillert 		    "d");
2216ac30837aSkrw 	if (p == NULL)
2217c33fcabaSmillert 		return;
2218c33fcabaSmillert 	switch (*p) {
2219c33fcabaSmillert 	case 'd':
2220c33fcabaSmillert 	case 'D':
2221c33fcabaSmillert 		if (dgp == NULL)
2222c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2223c33fcabaSmillert 		else {
2224c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
2225c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
2226c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
2227c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
2228c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
222934af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(dgp));
2230c33fcabaSmillert 		}
2231c33fcabaSmillert 		break;
2232c33fcabaSmillert 	case 'u':
2233c33fcabaSmillert 	case 'U':
2234c33fcabaSmillert 		if (ugp == NULL)
2235c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2236c33fcabaSmillert 		else {
2237c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2238c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2239c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2240c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2241c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
224234af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(ugp));
2243c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2244c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2245c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2246c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2247c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
224834af67a3Sotto 			    DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp))
2249c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2250c33fcabaSmillert 				    "geometry.\n", stderr);
2251c33fcabaSmillert 		}
2252c33fcabaSmillert 		break;
2253c33fcabaSmillert 	default:
22549a36aa41Ssthen 		fputs("You must enter either 'd' or 'u'.\n", stderr);
2255c33fcabaSmillert 		break;
2256c33fcabaSmillert 	}
2257c33fcabaSmillert }
22589afbe9eeSmillert 
22599afbe9eeSmillert void
22609fdcb4d6Skrw zero_partitions(struct disklabel *lp)
22619afbe9eeSmillert {
22629afbe9eeSmillert 	int i;
22639afbe9eeSmillert 
2264b4ed6301Skrw 	for (i = 0; i < MAXPARTITIONS; i++) {
22659afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
2266b4ed6301Skrw 		free(mountpoints[i]);
2267b4ed6301Skrw 		mountpoints[i] = NULL;
2268b4ed6301Skrw 	}
2269b4ed6301Skrw 
227034af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
22719afbe9eeSmillert }
227214192793Skrw 
227314192793Skrw u_int64_t
227414192793Skrw max_partition_size(struct disklabel *lp, int partno)
227514192793Skrw {
227614192793Skrw 	struct partition *pp = &lp->d_partitions[partno];
227714192793Skrw 	struct diskchunk *chunks;
227844ffe03bSotto 	u_int64_t maxsize = 0, offset;
227914192793Skrw 	int fstype, i;
228014192793Skrw 
228114192793Skrw 	fstype = pp->p_fstype;
228214192793Skrw 	pp->p_fstype = FS_UNUSED;
228314192793Skrw 	chunks = free_chunks(lp);
228414192793Skrw 	pp->p_fstype = fstype;
228514192793Skrw 
228614192793Skrw 	offset = DL_GETPOFFSET(pp);
228714192793Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
228814192793Skrw 		if (offset < chunks[i].start || offset >= chunks[i].stop)
228914192793Skrw 			continue;
229014192793Skrw 		maxsize = chunks[i].stop - offset;
229114192793Skrw 		break;
229214192793Skrw 	}
229314192793Skrw 	return (maxsize);
229414192793Skrw }
2295aff3f969Sotto 
2296aff3f969Sotto void
2297eafadddfSkrw psize(u_int64_t sz, char unit, struct disklabel *lp)
2298aff3f969Sotto {
2299aff3f969Sotto 	double d = scale(sz, unit, lp);
2300aff3f969Sotto 	if (d < 0)
2301aff3f969Sotto 		printf("%llu", sz);
2302aff3f969Sotto 	else
2303aff3f969Sotto 		printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
2304aff3f969Sotto }
2305aff3f969Sotto 
2306aff3f969Sotto void
23077ad973c1Skrw display_edit(struct disklabel *lp, char unit)
2308aff3f969Sotto {
23097ad973c1Skrw 	u_int64_t fr;
2310aff3f969Sotto 	int i;
2311aff3f969Sotto 
23127ad973c1Skrw 	fr = editor_countfree(lp);
2313352d199bSkrw 	unit = canonical_unit(lp, unit);
2314aff3f969Sotto 
2315aff3f969Sotto 	printf("OpenBSD area: ");
231659882f1dSkrw 	psize(starting_sector, 0, lp);
2317aff3f969Sotto 	printf("-");
231859882f1dSkrw 	psize(ending_sector, 0, lp);
2319aff3f969Sotto 	printf("; size: ");
2320aff3f969Sotto 	psize(ending_sector - starting_sector, unit, lp);
2321aff3f969Sotto 	printf("; free: ");
2322aff3f969Sotto 	psize(fr, unit, lp);
2323aff3f969Sotto 
2324aff3f969Sotto 	printf("\n#    %16.16s %16.16s  fstype [fsize bsize   cpg]\n",
2325aff3f969Sotto 	    "size", "offset");
2326aff3f969Sotto 	for (i = 0; i < lp->d_npartitions; i++)
232734ae4198Skrw 		display_partition(stdout, lp, i, unit);
2328aff3f969Sotto }
2329a2c1f847Shenning 
2330a2c1f847Shenning void
2331a2c1f847Shenning parse_autotable(char *filename)
2332a2c1f847Shenning {
2333a2c1f847Shenning 	FILE	*cfile;
2334*5f012d92Snaddy 	size_t	 linesize = 0;
2335*5f012d92Snaddy 	char	*line = NULL, *buf, *t;
2336a2c1f847Shenning 	uint	 idx = 0, pctsum = 0;
2337a2c1f847Shenning 	struct space_allocation *sa;
2338a2c1f847Shenning 
2339a2c1f847Shenning 	if ((cfile = fopen(filename, "r")) == NULL)
2340a2c1f847Shenning 		err(1, "%s", filename);
2341a2c1f847Shenning 	if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL)
2342a2c1f847Shenning 		err(1, NULL);
2343f55524eaSsthen 	alloc_table_nitems = 1;
2344a2c1f847Shenning 
2345*5f012d92Snaddy 	while (getline(&line, &linesize, cfile) != -1) {
2346a2c1f847Shenning 		if ((alloc_table[0].table = reallocarray(alloc_table[0].table,
2347a2c1f847Shenning 		    idx + 1, sizeof(*sa))) == NULL)
2348a2c1f847Shenning 			err(1, NULL);
2349a2c1f847Shenning 		sa = &(alloc_table[0].table[idx]);
2350ee18520dSotto 		memset(sa, 0, sizeof(*sa));
2351a2c1f847Shenning 		idx++;
2352a2c1f847Shenning 
2353*5f012d92Snaddy 		buf = line;
235458c7d7acSnaddy 		if ((sa->mp = get_token(&buf)) == NULL ||
2355a2c1f847Shenning 		    (sa->mp[0] != '/' && strcmp(sa->mp, "swap")))
2356a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
235758c7d7acSnaddy 		if ((t = get_token(&buf)) == NULL ||
2358a2c1f847Shenning 		    parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1)
2359a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
236058c7d7acSnaddy 		if ((t = get_token(&buf)) != NULL &&
2361a2c1f847Shenning 		    parse_pct(t, &sa->rate) == -1)
2362a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
2363a2c1f847Shenning 		if (sa->minsz > sa->maxsz)
2364a2c1f847Shenning 			errx(1, "%s: min size > max size on line %u", filename,
2365a2c1f847Shenning 			    idx);
2366a2c1f847Shenning 		pctsum += sa->rate;
2367a2c1f847Shenning 	}
2368a2c1f847Shenning 	if (pctsum > 100)
2369a2c1f847Shenning 		errx(1, "%s: sum of extra space allocation > 100%%", filename);
2370a2c1f847Shenning 	alloc_table[0].sz = idx;
2371*5f012d92Snaddy 	free(line);
2372a2c1f847Shenning 	fclose(cfile);
2373a2c1f847Shenning }
2374a2c1f847Shenning 
2375a2c1f847Shenning char *
237658c7d7acSnaddy get_token(char **s)
2377a2c1f847Shenning {
2378a2c1f847Shenning 	char	*p, *r;
2379a2c1f847Shenning 	size_t	 tlen = 0;
2380a2c1f847Shenning 
2381a2c1f847Shenning 	p = *s;
238258c7d7acSnaddy 	while (**s != '\0' && !isspace((u_char)**s)) {
2383a2c1f847Shenning 		(*s)++;
2384a2c1f847Shenning 		tlen++;
2385a2c1f847Shenning 	}
2386a2c1f847Shenning 	if (tlen == 0)
2387a2c1f847Shenning 		return (NULL);
2388a2c1f847Shenning 
2389a2c1f847Shenning 	/* eat whitespace */
239058c7d7acSnaddy 	while (isspace((u_char)**s))
2391a2c1f847Shenning 		(*s)++;
2392a2c1f847Shenning 
2393104c1c3cSmillert 	if ((r = strndup(p, tlen)) == NULL)
2394a2c1f847Shenning 		err(1, NULL);
2395a2c1f847Shenning 	return (r);
2396a2c1f847Shenning }
2397a2c1f847Shenning 
2398a2c1f847Shenning int
2399a2c1f847Shenning apply_unit(double val, u_char unit, u_int64_t *n)
2400a2c1f847Shenning {
2401a2c1f847Shenning 	u_int64_t factor = 1;
2402a2c1f847Shenning 
2403a2c1f847Shenning 	switch (tolower(unit)) {
2404a2c1f847Shenning 	case 't':
2405a2c1f847Shenning 		factor *= 1024;
2406a2c1f847Shenning 		/* FALLTHROUGH */
2407a2c1f847Shenning 	case 'g':
2408a2c1f847Shenning 		factor *= 1024;
2409a2c1f847Shenning 		/* FALLTHROUGH */
2410a2c1f847Shenning 	case 'm':
2411a2c1f847Shenning 		factor *= 1024;
2412a2c1f847Shenning 		/* FALLTHROUGH */
2413a2c1f847Shenning 	case 'k':
2414a2c1f847Shenning 		factor *= 1024;
2415a2c1f847Shenning 		break;
2416a2c1f847Shenning 	default:
2417a2c1f847Shenning 		return (-1);
2418a2c1f847Shenning 	}
2419a2c1f847Shenning 
2420a2c1f847Shenning 	val *= factor / DEV_BSIZE;
2421a2c1f847Shenning 	if (val > ULLONG_MAX)
2422a2c1f847Shenning 		return (-1);
2423a2c1f847Shenning 	*n = val;
2424a2c1f847Shenning 	return (0);
2425a2c1f847Shenning }
2426a2c1f847Shenning 
2427a2c1f847Shenning int
2428a2c1f847Shenning parse_sizespec(const char *buf, double *val, char **unit)
2429a2c1f847Shenning {
24305f6cf98aSkrw 	errno = 0;
2431a2c1f847Shenning 	*val = strtod(buf, unit);
24325f6cf98aSkrw 	if (errno == ERANGE || *val < 0 || *val > ULLONG_MAX)
24335f6cf98aSkrw 		return (-1);	/* too big/small */
24345f6cf98aSkrw 	if (*val == 0 && *unit == buf)
24355f6cf98aSkrw 		return (-1);	/* No conversion performed. */
2436a2c1f847Shenning 	if (*unit != NULL && *unit[0] == '\0')
2437a2c1f847Shenning 		*unit = NULL;
2438a2c1f847Shenning 	return (0);
2439a2c1f847Shenning }
2440a2c1f847Shenning 
2441a2c1f847Shenning int
2442a2c1f847Shenning parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max)
2443a2c1f847Shenning {
2444a2c1f847Shenning 	char	*p, *unit1 = NULL, *unit2 = NULL;
2445a2c1f847Shenning 	double	 val1 = 0, val2 = 0;
2446a2c1f847Shenning 
2447a2c1f847Shenning 	if ((p = strchr(buf, '-')) != NULL) {
2448a2c1f847Shenning 		p[0] = '\0';
2449a2c1f847Shenning 		p++;
2450a2c1f847Shenning 	}
2451a2c1f847Shenning 	*max = 0;
2452a2c1f847Shenning 	if (parse_sizespec(buf, &val1, &unit1) == -1)
2453a2c1f847Shenning 		return (-1);
2454a2c1f847Shenning 	if (p != NULL && p[0] != '\0') {
2455a2c1f847Shenning 		if (p[0] == '*')
2456a2c1f847Shenning 			*max = -1;
2457a2c1f847Shenning 		else
2458a2c1f847Shenning 			if (parse_sizespec(p, &val2, &unit2) == -1)
2459a2c1f847Shenning 				return (-1);
2460a2c1f847Shenning 	}
2461a2c1f847Shenning 	if (unit1 == NULL && (unit1 = unit2) == NULL)
2462a2c1f847Shenning 		return (-1);
2463a2c1f847Shenning 	if (apply_unit(val1, unit1[0], min) == -1)
2464a2c1f847Shenning 		return (-1);
2465a2c1f847Shenning 	if (val2 > 0) {
2466a2c1f847Shenning 		if (apply_unit(val2, unit2[0], max) == -1)
2467a2c1f847Shenning 			return (-1);
2468a2c1f847Shenning 	} else
2469a2c1f847Shenning 		if (*max == 0)
2470a2c1f847Shenning 			*max = *min;
2471a2c1f847Shenning 	free(buf);
2472a2c1f847Shenning 	return (0);
2473a2c1f847Shenning }
2474a2c1f847Shenning 
2475a2c1f847Shenning int
2476a2c1f847Shenning parse_pct(char *buf, int *n)
2477a2c1f847Shenning {
2478a2c1f847Shenning 	const char	*errstr;
2479a2c1f847Shenning 
2480a2c1f847Shenning 	if (buf[strlen(buf) - 1] == '%')
2481a2c1f847Shenning 		buf[strlen(buf) - 1] = '\0';
2482a2c1f847Shenning 	*n = strtonum(buf, 0, 100, &errstr);
2483a2c1f847Shenning 	if (errstr) {
2484a2c1f847Shenning 		warnx("parse percent %s: %s", buf, errstr);
2485a2c1f847Shenning 		return (-1);
2486a2c1f847Shenning 	}
2487a2c1f847Shenning 	free(buf);
2488a2c1f847Shenning 	return (0);
2489a2c1f847Shenning }
249040b226e8Skrw 
249140b226e8Skrw int
249240b226e8Skrw alignpartition(struct disklabel *lp, int partno, u_int64_t startalign,
249340b226e8Skrw     u_int64_t stopalign, int flags)
249440b226e8Skrw {
249540b226e8Skrw 	struct partition *pp = &lp->d_partitions[partno];
249640b226e8Skrw 	struct diskchunk *chunks;
249740b226e8Skrw 	u_int64_t start, stop, maxstop;
249840b226e8Skrw 	unsigned int i;
249940b226e8Skrw 	u_int8_t fstype;
250040b226e8Skrw 
250140b226e8Skrw 	start = DL_GETPOFFSET(pp);
250240b226e8Skrw 	if ((flags & ROUND_OFFSET_UP) == ROUND_OFFSET_UP)
250340b226e8Skrw 		start = ((start + startalign - 1) / startalign) * startalign;
250440b226e8Skrw 	else if ((flags & ROUND_OFFSET_DOWN) == ROUND_OFFSET_DOWN)
250540b226e8Skrw 		start = (start / startalign) * startalign;
250640b226e8Skrw 
250740b226e8Skrw 	/* Find the chunk that contains 'start'. */
250840b226e8Skrw 	fstype = pp->p_fstype;
250940b226e8Skrw 	pp->p_fstype = FS_UNUSED;
251040b226e8Skrw 	chunks = free_chunks(lp);
251140b226e8Skrw 	pp->p_fstype = fstype;
251240b226e8Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
251340b226e8Skrw 		if (start >= chunks[i].start && start < chunks[i].stop)
251440b226e8Skrw 			break;
251540b226e8Skrw 	}
251640b226e8Skrw 	if (chunks[i].stop == 0) {
2517aef735d2Skrw 		fprintf(stderr, "'%c' aligned offset %llu lies outside "
2518aef735d2Skrw 		    "the OpenBSD bounds or inside another partition\n",
2519aef735d2Skrw 		    'a' + partno, start);
252040b226e8Skrw 		return (1);
252140b226e8Skrw 	}
252240b226e8Skrw 
252340b226e8Skrw 	/* Calculate the new 'stop' sector, the sector after the partition. */
2524aef735d2Skrw 	if ((flags & ROUND_SIZE_OVERLAP) == 0)
2525aef735d2Skrw 		maxstop = (chunks[i].stop / stopalign) * stopalign;
2526aef735d2Skrw 	else
2527aef735d2Skrw 		maxstop = (ending_sector / stopalign) * stopalign;
2528aef735d2Skrw 
252940b226e8Skrw 	stop = DL_GETPOFFSET(pp) + DL_GETPSIZE(pp);
253040b226e8Skrw 	if ((flags & ROUND_SIZE_UP) == ROUND_SIZE_UP)
253140b226e8Skrw 		stop = ((stop + stopalign - 1) / stopalign) * stopalign;
253240b226e8Skrw 	else if ((flags & ROUND_SIZE_DOWN) == ROUND_SIZE_DOWN)
253340b226e8Skrw 		stop = (stop / stopalign) * stopalign;
2534aef735d2Skrw 	if (stop > maxstop)
253540b226e8Skrw 		stop = maxstop;
253640b226e8Skrw 
2537aef735d2Skrw 	if (stop <= start) {
2538aef735d2Skrw 		fprintf(stderr, "'%c' aligned size <= 0\n", 'a' + partno);
2539aef735d2Skrw 		return (1);
2540aef735d2Skrw 	}
2541aef735d2Skrw 
254240b226e8Skrw 	if (start != DL_GETPOFFSET(pp))
254340b226e8Skrw 		DL_SETPOFFSET(pp, start);
2544aef735d2Skrw 	if (stop != DL_GETPOFFSET(pp) + DL_GETPSIZE(pp))
254540b226e8Skrw 		DL_SETPSIZE(pp, stop - start);
254640b226e8Skrw 
254740b226e8Skrw 	return (0);
254840b226e8Skrw }
2549