xref: /openbsd/sbin/disklabel/editor.c (revision 44ffe03b)
1*44ffe03bSotto /*	$OpenBSD: editor.c,v 1.228 2010/03/23 14:59:30 otto Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
42d8451b0Smillert  * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert  */
186fe57b42Smillert 
196fe57b42Smillert #include <sys/types.h>
206fe57b42Smillert #include <sys/param.h>
21c33fcabaSmillert #include <sys/stat.h>
22c33fcabaSmillert #include <sys/ioctl.h>
238dde8bb6Sotto #include <sys/sysctl.h>
246fe57b42Smillert #define	DKTYPENAMES
256fe57b42Smillert #include <sys/disklabel.h>
266fe57b42Smillert 
276fe57b42Smillert #include <ufs/ffs/fs.h>
286fe57b42Smillert 
296fe57b42Smillert #include <ctype.h>
306fe57b42Smillert #include <err.h>
316fe57b42Smillert #include <errno.h>
326fe57b42Smillert #include <string.h>
33803ff7d5Smillert #include <libgen.h>
346fe57b42Smillert #include <stdio.h>
356fe57b42Smillert #include <stdlib.h>
366fe57b42Smillert #include <unistd.h>
376fe57b42Smillert 
38f21a098bSotto #include "extern.h"
394793b14cSmillert #include "pathnames.h"
404793b14cSmillert 
416fe57b42Smillert /* flags for getuint() */
426fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
436fe57b42Smillert #define	DO_ROUNDING	0x00000002
446fe57b42Smillert 
45f98aebd4Smillert #ifndef NUMBOOT
46f98aebd4Smillert #define NUMBOOT 0
47f98aebd4Smillert #endif
48f98aebd4Smillert 
4996a888c6Smillert /* structure to describe a portion of a disk */
5096a888c6Smillert struct diskchunk {
511e0ad43cSotto 	u_int64_t start;
521e0ad43cSotto 	u_int64_t stop;
5396a888c6Smillert };
5496a888c6Smillert 
553f843443Smillert /* used when sorting mountpoints in mpsave() */
563f843443Smillert struct mountinfo {
573f843443Smillert 	char *mountpoint;
583f843443Smillert 	int partno;
593f843443Smillert };
603f843443Smillert 
61557f712bSkrw /* used when allocating all space according to recommendations */
62557f712bSkrw 
63557f712bSkrw struct space_allocation {
645f3e1104Skrw 	daddr64_t	minsz;	/* starts as blocks, xlated to sectors. */
655f3e1104Skrw 	daddr64_t	maxsz;	/* starts as blocks, xlated to sectors. */
66557f712bSkrw 	int		rate;	/* % of extra space to use */
67557f712bSkrw 	char 	       *mp;
68557f712bSkrw };
69557f712bSkrw 
708dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
718dde8bb6Sotto const struct space_allocation alloc_big[] = {
7292adb55fSderaadt 	{   MEG(80),         GIG(1),   5, "/"		},
738dde8bb6Sotto 	{   MEG(80),       MEG(256),   5, "swap"	},
744ab111d2Sderaadt 	{  MEG(120),         GIG(4),   8, "/tmp"	},
7592adb55fSderaadt 	{   MEG(80),         GIG(4),  13, "/var"	},
7621a0d117Sderaadt 	{  MEG(900),         GIG(2),   5, "/usr"	},
7792adb55fSderaadt 	{  MEG(512),         GIG(1),   3, "/usr/X11R6"	},
7892adb55fSderaadt 	{    GIG(2),         GIG(6),   5, "/usr/local"	},
7992adb55fSderaadt 	{    GIG(1),         GIG(2),   3, "/usr/src"	},
8092adb55fSderaadt 	{    GIG(1),         GIG(2),   3, "/usr/obj"	},
8121a0d117Sderaadt 	{    GIG(1),       GIG(300),  50, "/home"	}
824ab111d2Sderaadt 	/* Anything beyond this leave for the user to decide */
838dde8bb6Sotto };
848dde8bb6Sotto 
858dde8bb6Sotto const struct space_allocation alloc_medium[] = {
86905e8239Sderaadt 	{  MEG(800),         GIG(2),   5, "/"		},
878dde8bb6Sotto 	{   MEG(80),       MEG(256),  10, "swap"	},
88905e8239Sderaadt 	{  MEG(900),         GIG(3),  78, "/usr"	},
89905e8239Sderaadt 	{  MEG(256),         GIG(2),   7, "/home"	}
908dde8bb6Sotto };
918dde8bb6Sotto 
928dde8bb6Sotto const struct space_allocation alloc_small[] = {
9392adb55fSderaadt 	{  MEG(700),         GIG(4),  95, "/"		},
948dde8bb6Sotto 	{    MEG(1),       MEG(256),   5, "swap"	}
958dde8bb6Sotto };
968dde8bb6Sotto 
978dde8bb6Sotto const struct space_allocation alloc_stupid[] = {
988dde8bb6Sotto 	{    MEG(1),      MEG(2048), 100, "/"		}
998dde8bb6Sotto };
1008dde8bb6Sotto 
101b2813ff1Sderaadt #ifndef nitems
102b2813ff1Sderaadt #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
103b2813ff1Sderaadt #endif
104b2813ff1Sderaadt 
1058a862940Sderaadt const struct {
1068a862940Sderaadt 	const struct space_allocation *table;
1078a862940Sderaadt 	int sz;
1088a862940Sderaadt } alloc_table[] = {
1098dde8bb6Sotto 	{ alloc_big,	nitems(alloc_big) },
1108dde8bb6Sotto 	{ alloc_medium,	nitems(alloc_medium) },
1118dde8bb6Sotto 	{ alloc_small,	nitems(alloc_small) },
1128dde8bb6Sotto 	{ alloc_stupid,	nitems(alloc_stupid) }
113557f712bSkrw };
114557f712bSkrw 
1159fdcb4d6Skrw void	edit_parms(struct disklabel *);
1166aaa4aabSotto void	editor_resize(struct disklabel *, char *);
11734ae4198Skrw void	editor_add(struct disklabel *, char *);
1189fdcb4d6Skrw void	editor_change(struct disklabel *, char *);
1199fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *);
12034ae4198Skrw void	editor_delete(struct disklabel *, char *);
121c72b5b24Smillert void	editor_help(char *);
12234ae4198Skrw void	editor_modify(struct disklabel *, char *);
12334ae4198Skrw void	editor_name(struct disklabel *, char *);
124c72b5b24Smillert char	*getstring(char *, char *, char *);
125dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int);
1261f0f871dSkrw int	has_overlap(struct disklabel *);
127c72b5b24Smillert int	partition_cmp(const void *, const void *);
1280fbd3c97Skrw struct partition **sort_partitions(struct disklabel *);
129c72b5b24Smillert void	getdisktype(struct disklabel *, char *, char *);
13087023ed9Skrw void	find_bounds(struct disklabel *);
1319fdcb4d6Skrw void	set_bounds(struct disklabel *);
132c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *);
1334f3bbbf0Skrw void	mpcopy(char **, char **);
134c72b5b24Smillert int	micmp(const void *, const void *);
135c72b5b24Smillert int	mpequal(char **, char **);
136c72b5b24Smillert int	get_bsize(struct disklabel *, int);
137c72b5b24Smillert int	get_fsize(struct disklabel *, int);
138c72b5b24Smillert int	get_fstype(struct disklabel *, int);
13934ae4198Skrw int	get_mp(struct disklabel *, int);
140604d3bdeSkrw int	get_offset(struct disklabel *, int);
1419fdcb4d6Skrw int	get_size(struct disklabel *, int);
14287023ed9Skrw void	get_geometry(int, struct disklabel **);
14387023ed9Skrw void	set_geometry(struct disklabel *, struct disklabel *, struct disklabel *,
14487023ed9Skrw 	    char *);
1459fdcb4d6Skrw void	zero_partitions(struct disklabel *);
14614192793Skrw u_int64_t max_partition_size(struct disklabel *, int);
14734ae4198Skrw void	display_edit(struct disklabel *, char, u_int64_t);
14896a888c6Smillert 
1491e0ad43cSotto static u_int64_t starting_sector;
1501e0ad43cSotto static u_int64_t ending_sector;
1512d8451b0Smillert static int expert;
1526aaa4aabSotto static int spoofed;
1536fe57b42Smillert 
1546fe57b42Smillert /*
1554d4a335eSkrw  * Simple partition editor.
1566fe57b42Smillert  */
1576fe57b42Smillert int
15834ae4198Skrw editor(struct disklabel *lp, int f)
1596fe57b42Smillert {
1604f3bbbf0Skrw 	struct disklabel origlabel, lastlabel, tmplabel, label = *lp;
1617e28fb0fSderaadt 	struct disklabel *disk_geop = NULL;
16296a888c6Smillert 	struct partition *pp;
1636fe57b42Smillert 	FILE *fp;
1646fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
16534ae4198Skrw 	char **omountpoints = NULL;
1664f3bbbf0Skrw 	char **origmountpoints = NULL, **tmpmountpoints = NULL;
1677e28fb0fSderaadt 	int i, error = 0;
168bd6726faSmillert 
169bd6726faSmillert 	/* Alloc and init mount point info */
17034ae4198Skrw 	if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
1714f3bbbf0Skrw 	    !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
172bd6726faSmillert 	    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
173bd6726faSmillert 		errx(4, "out of memory");
1746fe57b42Smillert 
17596a888c6Smillert 	/* Don't allow disk type of "unknown" */
17634ae4198Skrw 	getdisktype(&label, "You need to specify a type for this disk.", specname);
1776fe57b42Smillert 
17887023ed9Skrw 	/* Get the on-disk geometries if possible */
17987023ed9Skrw 	get_geometry(f, &disk_geop);
180c33fcabaSmillert 
181d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
18287023ed9Skrw 	find_bounds(&label);
183d09f3941Smillert 
18496a888c6Smillert 	/* Make sure there is no partition overlap. */
1851f0f871dSkrw 	if (has_overlap(&label))
1866fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1876fe57b42Smillert 
18896a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
189d09f3941Smillert 	pp = &label.d_partitions[RAW_PART];
1901e0ad43cSotto 	if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) {
19196a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
19296a888c6Smillert 		if (label.d_npartitions < 3)
19396a888c6Smillert 			label.d_npartitions = 3;
19434af67a3Sotto 		DL_SETPOFFSET(pp, 0);
19534af67a3Sotto 		DL_SETPSIZE(pp, DL_GETDSIZE(&label));
19696a888c6Smillert 		pp->p_fstype = FS_UNUSED;
197ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
19896a888c6Smillert 	}
1990f820bbbSmillert 
200fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
201fc1a4cc6Sderaadt 	if (label.d_flags & D_VENDOR) {
202fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
203fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
204fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
205fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
206fc1a4cc6Sderaadt 	}
2076fe57b42Smillert #endif
2086fe57b42Smillert 
209bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
21055403f76Smillert 	if (label.d_bbsize == 0)
21155403f76Smillert 		label.d_bbsize = BBSIZE;
21255403f76Smillert 	if (label.d_sbsize == 0)
21355403f76Smillert 		label.d_sbsize = SBSIZE;
214f98aebd4Smillert 
215440b1d70Smillert 	/* Interleave must be >= 1 */
216440b1d70Smillert 	if (label.d_interleave == 0)
217440b1d70Smillert 		label.d_interleave = 1;
218440b1d70Smillert 
21993160b9bSkrw 	/* Save the (U|u)ndo labels and mountpoints. */
22093160b9bSkrw 	mpcopy(origmountpoints, mountpoints);
2214f3bbbf0Skrw 	origlabel = label;
2226fe57b42Smillert 	lastlabel = label;
22334ae4198Skrw 
22434ae4198Skrw 	puts("Label editor (enter '?' for help at any prompt)");
2256fe57b42Smillert 	for (;;) {
2266fe57b42Smillert 		fputs("> ", stdout);
2276e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2286e0becc5Smillert 			putchar('\n');
2296e0becc5Smillert 			buf[0] = 'q';
2306e0becc5Smillert 			buf[1] = '\0';
2316e0becc5Smillert 		}
232260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
233260513deSmillert 			continue;
234260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2356fe57b42Smillert 
2364f3bbbf0Skrw 		if ((*cmd != 'u') && (*cmd != 'U')) {
2374f3bbbf0Skrw 			/*
2384f3bbbf0Skrw 			 * Save undo info in case the command tries to make
2394f3bbbf0Skrw 			 * changes but decides not to.
2404f3bbbf0Skrw 			 */
2414f3bbbf0Skrw 			tmplabel = lastlabel;
2424f3bbbf0Skrw 			lastlabel = label;
2434f3bbbf0Skrw 			mpcopy(tmpmountpoints, omountpoints);
2444f3bbbf0Skrw 			mpcopy(omountpoints, mountpoints);
2454f3bbbf0Skrw 		}
2466fe57b42Smillert 
2474f3bbbf0Skrw 		switch (*cmd) {
2486fe57b42Smillert 		case '?':
249ea37abd3Sderaadt 		case 'h':
250617e6e4aSmillert 			editor_help(arg ? arg : "");
2516fe57b42Smillert 			break;
2526fe57b42Smillert 
253557f712bSkrw 		case 'A':
254ab20a3eaSkrw 			if (ioctl(f, DIOCGPDINFO, &label) == 0) {
255ab20a3eaSkrw 				aflag = 1;
25634ae4198Skrw 				editor_allocspace(&label);
257ab20a3eaSkrw 			} else
25834ae4198Skrw 				label = lastlabel;
259557f712bSkrw 			break;
2606fe57b42Smillert 		case 'a':
26134ae4198Skrw 			editor_add(&label, arg);
26296a888c6Smillert 			break;
26396a888c6Smillert 
26496a888c6Smillert 		case 'b':
2659fdcb4d6Skrw 			set_bounds(&label);
2666fe57b42Smillert 			break;
2676fe57b42Smillert 
2686fe57b42Smillert 		case 'c':
2699fdcb4d6Skrw 			editor_change(&label, arg);
2706fe57b42Smillert 			break;
2716fe57b42Smillert 
2729afbe9eeSmillert 		case 'D':
27393160b9bSkrw 			if (ioctl(f, DIOCGPDINFO, &label) == 0) {
27471bba4ecSkrw 				dflag = 1;
27593160b9bSkrw 				for (i=0; i<MAXPARTITIONS; i++) {
27693160b9bSkrw 					free(mountpoints[i]);
27793160b9bSkrw 					mountpoints[i] = NULL;
27893160b9bSkrw 				}
27993160b9bSkrw 			} else
280cdd7eb76Smillert 				warn("unable to get default partition table");
2819afbe9eeSmillert 			break;
2829afbe9eeSmillert 
2836fe57b42Smillert 		case 'd':
28434ae4198Skrw 			editor_delete(&label, arg);
2856fe57b42Smillert 			break;
2866fe57b42Smillert 
2879afbe9eeSmillert 		case 'e':
2889fdcb4d6Skrw 			edit_parms(&label);
2899afbe9eeSmillert 			break;
2909afbe9eeSmillert 
291c33fcabaSmillert 		case 'g':
29287023ed9Skrw 			set_geometry(&label, disk_geop, lp, arg);
293c33fcabaSmillert 			break;
294c33fcabaSmillert 
2956fe57b42Smillert 		case 'm':
29634ae4198Skrw 			editor_modify(&label, arg);
297bd6726faSmillert 			break;
298bd6726faSmillert 
299bd6726faSmillert 		case 'n':
3005c79e1cfSkrw 			if (!fstabfile) {
301bd6726faSmillert 				fputs("This option is not valid when run "
30284d0bb16Sderaadt 				    "without the -f flag.\n", stderr);
303bd6726faSmillert 				break;
304bd6726faSmillert 			}
30534ae4198Skrw 			editor_name(&label, arg);
3066fe57b42Smillert 			break;
3076fe57b42Smillert 
3086fe57b42Smillert 		case 'p':
30934ae4198Skrw 			display_edit(&label, arg ? *arg : 0, editor_countfree(&label));
3106fe57b42Smillert 			break;
3116fe57b42Smillert 
312aff3f969Sotto 		case 'l':
31334ae4198Skrw 			display(stdout, &label, arg ? *arg : 0, 0);
314aff3f969Sotto 			break;
315aff3f969Sotto 
316508086e9Smillert 		case 'M': {
317508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
31845decb36Sderaadt 			char *pager, *comm = NULL;
319e7936562Sderaadt 			extern const u_char manpage[];
32008f8e31fSotto 			extern const int manpage_sz;
3215d12b01bSderaadt 
322489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
323508086e9Smillert 				pager = _PATH_LESS;
32408f8e31fSotto 
32545decb36Sderaadt 			if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
32645decb36Sderaadt 			    (fp = popen(comm, "w")) != NULL) {
32708f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3285d12b01bSderaadt 				pclose(fp);
329508086e9Smillert 			} else
330508086e9Smillert 				warn("unable to execute %s", pager);
331508086e9Smillert 
33245decb36Sderaadt 			free(comm);
333508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3345d12b01bSderaadt 			break;
335508086e9Smillert 		}
3365d12b01bSderaadt 
3376fe57b42Smillert 		case 'q':
33869220492Smillert 			if (donothing) {
33969220492Smillert 				puts("In no change mode, not writing label.");
3407e28fb0fSderaadt 				goto done;
34169220492Smillert 			}
342bd6726faSmillert 			/* Save mountpoint info if there is any. */
34334ae4198Skrw 			mpsave(&label);
34493160b9bSkrw 
34571bba4ecSkrw                         /*
34693160b9bSkrw 			 * If we haven't changed the original label, and it
34793160b9bSkrw 			 * wasn't a default label or an auto-allocated label,
34893160b9bSkrw 			 * there is no need to do anything before exiting. Note
34993160b9bSkrw 			 * that 'w' will reset dflag and aflag to allow 'q' to
35093160b9bSkrw 			 * exit without further questions.
35171bba4ecSkrw  			 */
352ab20a3eaSkrw 			if (!dflag && !aflag &&
353ab20a3eaSkrw 			    memcmp(lp, &label, sizeof(label)) == 0) {
354bd6726faSmillert 				puts("No label changes.");
3557e28fb0fSderaadt 				goto done;
3566fe57b42Smillert 			}
3576fe57b42Smillert 			do {
358d0e67762Smillert 				arg = getstring("Write new label?",
359d0e67762Smillert 				    "Write the modified label to disk?",
360d0e67762Smillert 				    "y");
36196a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
36296a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
363d0e67762Smillert 				if (writelabel(f, bootarea, &label) == 0) {
3646fe57b42Smillert 					*lp = label;
3657e28fb0fSderaadt 					goto done;
3666fe57b42Smillert 				}
367d0e67762Smillert 				warnx("unable to write label");
368d0e67762Smillert 			}
3697e28fb0fSderaadt 			error = 1;
3707e28fb0fSderaadt 			goto done;
3716fe57b42Smillert 			/* NOTREACHED */
3726fe57b42Smillert 			break;
3736fe57b42Smillert 
3746aaa4aabSotto 		case 'R':
3756aaa4aabSotto 			if (aflag && !spoofed)
3766aaa4aabSotto 				editor_resize(&label, arg);
3776aaa4aabSotto 			else
3786aaa4aabSotto 				fputs("Resize only implemented for auto "
3796aaa4aabSotto 				    "allocated labels without spoofed "
3806aaa4aabSotto 				    "partitions\n", stderr);
3816aaa4aabSotto 			break;
3826aaa4aabSotto 
38325f9c360Skrw 		case 'r': {
38425f9c360Skrw 			struct diskchunk *chunks;
38525f9c360Skrw 			int i;
3869fdcb4d6Skrw 			/* Display free space. */
38725f9c360Skrw 			chunks = free_chunks(&label);
38825f9c360Skrw 			for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0;
38925f9c360Skrw 			    i++)
39025f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
39125f9c360Skrw 				    "(%16llu)\n",
39225f9c360Skrw 			    	    chunks[i].start, chunks[i].stop - 1,
39325f9c360Skrw 			   	    chunks[i].stop - chunks[i].start);
39425f9c360Skrw 			fprintf(stderr, "Total free sectors: %llu.\n",
3959fdcb4d6Skrw 			    editor_countfree(&label));
396c0bdc608Smillert 		    	break;
39725f9c360Skrw 		}
398c0bdc608Smillert 
3996fe57b42Smillert 		case 's':
4006fe57b42Smillert 			if (arg == NULL) {
401c33fcabaSmillert 				arg = getstring("Filename",
4026fe57b42Smillert 				    "Name of the file to save label into.",
4036fe57b42Smillert 				    NULL);
404e97229a3Scnst 				if (arg == NULL || *arg == '\0')
4056fe57b42Smillert 					break;
4066fe57b42Smillert 			}
4076fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
4086fe57b42Smillert 				warn("cannot open %s", arg);
4096fe57b42Smillert 			} else {
41034ae4198Skrw 				display(fp, &label, 0, 1);
4116fe57b42Smillert 				(void)fclose(fp);
4126fe57b42Smillert 			}
4136fe57b42Smillert 			break;
4146fe57b42Smillert 
4154f3bbbf0Skrw 		case 'U':
41693160b9bSkrw 			/*
41793160b9bSkrw 			 * If we allow 'U' repeatedly, information would be lost. This way
41893160b9bSkrw 			 * multiple 'U's followed by 'u' would undo the 'U's.
41993160b9bSkrw 			 */
42093160b9bSkrw 			if (memcmp(&label, &origlabel, sizeof(label)) ||
42193160b9bSkrw 			    !mpequal(mountpoints, origmountpoints)) {
4224f3bbbf0Skrw 				tmplabel = label;
4234f3bbbf0Skrw 				label = origlabel;
4244f3bbbf0Skrw 				lastlabel = tmplabel;
4254f3bbbf0Skrw 				mpcopy(tmpmountpoints, mountpoints);
4264f3bbbf0Skrw 				mpcopy(mountpoints, origmountpoints);
4274f3bbbf0Skrw 				mpcopy(omountpoints, tmpmountpoints);
4284f3bbbf0Skrw 			}
42993160b9bSkrw 			puts("Original label and mount points restored.");
4304f3bbbf0Skrw 			break;
4314f3bbbf0Skrw 
4326fe57b42Smillert 		case 'u':
4336fe57b42Smillert 			tmplabel = label;
4346fe57b42Smillert 			label = lastlabel;
4356fe57b42Smillert 			lastlabel = tmplabel;
4364f3bbbf0Skrw 			mpcopy(tmpmountpoints, mountpoints);
437bd6726faSmillert 			mpcopy(mountpoints, omountpoints);
4384f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4396fe57b42Smillert 			puts("Last change undone.");
4406fe57b42Smillert 			break;
4416fe57b42Smillert 
442040947cfSmillert 		case 'w':
443bd6726faSmillert 			if (donothing)  {
444040947cfSmillert 				puts("In no change mode, not writing label.");
445bd6726faSmillert 				break;
446bd6726faSmillert 			}
44793160b9bSkrw 
44841f684b9Skrw 			/* Write label to disk. */
44941f684b9Skrw 			if (writelabel(f, bootarea, &label) != 0)
450040947cfSmillert 				warnx("unable to write label");
45171bba4ecSkrw 			else {
452ab20a3eaSkrw 				dflag = aflag = 0;
4535af08e9cSmillert 				*lp = label;
45471bba4ecSkrw 			}
455040947cfSmillert 			break;
456040947cfSmillert 
4572d8451b0Smillert 		case 'X':
4582d8451b0Smillert 			expert = !expert;
4592d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
4602d8451b0Smillert 			    "Exiting");
4612d8451b0Smillert 			break;
4622d8451b0Smillert 
4636fe57b42Smillert 		case 'x':
4647e28fb0fSderaadt 			goto done;
4656fe57b42Smillert 			break;
4666fe57b42Smillert 
4679afbe9eeSmillert 		case 'z':
4689fdcb4d6Skrw 			zero_partitions(&label);
4696fe57b42Smillert 			break;
4706fe57b42Smillert 
4719afbe9eeSmillert 		case '\n':
4726fe57b42Smillert 			break;
4736fe57b42Smillert 
4746fe57b42Smillert 		default:
4756fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4766fe57b42Smillert 			break;
4776fe57b42Smillert 		}
4784f3bbbf0Skrw 
4794f3bbbf0Skrw 		/*
4804f3bbbf0Skrw 		 * If no changes were made to label or mountpoints, then
4814f3bbbf0Skrw 		 * restore undo info.
4824f3bbbf0Skrw 		 */
4834f3bbbf0Skrw 		if (memcmp(&label, &lastlabel, sizeof(label)) == 0 &&
48493160b9bSkrw 		    (mpequal(mountpoints, omountpoints))) {
4854f3bbbf0Skrw 			lastlabel = tmplabel;
4864f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4874f3bbbf0Skrw 		}
4886fe57b42Smillert 	}
4897e28fb0fSderaadt done:
4907e28fb0fSderaadt 	free(omountpoints);
4917e28fb0fSderaadt 	free(origmountpoints);
4927e28fb0fSderaadt 	free(tmpmountpoints);
4937e28fb0fSderaadt 	if (disk_geop)
4947e28fb0fSderaadt 		free(disk_geop);
4957e28fb0fSderaadt 	return(error);
4966fe57b42Smillert }
4976fe57b42Smillert 
4988dde8bb6Sotto int64_t
4998dde8bb6Sotto getphysmem(void)
5008dde8bb6Sotto {
5018dde8bb6Sotto 	int64_t physmem;
5028dde8bb6Sotto 	size_t sz = sizeof(physmem);
5038dde8bb6Sotto 	int mib[] = { CTL_HW, HW_PHYSMEM64 };
5048dde8bb6Sotto 	if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1)
5058dde8bb6Sotto 		errx(4, "can't get mem size");
5068dde8bb6Sotto 	return physmem;
5078dde8bb6Sotto }
5088dde8bb6Sotto 
5096fe57b42Smillert /*
510557f712bSkrw  * Allocate all disk space according to standard recommendations for a
511557f712bSkrw  * root disk.
512557f712bSkrw  */
513557f712bSkrw void
5148dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
515557f712bSkrw {
5168dde8bb6Sotto 	struct disklabel *lp, label;
5178dde8bb6Sotto 	struct space_allocation *alloc;
51834ae4198Skrw 	struct space_allocation *ap;
519557f712bSkrw 	struct partition *pp;
52034ae4198Skrw 	struct diskchunk *chunks;
52134ae4198Skrw 	daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs;
52234ae4198Skrw 	char **partmp;
5236e312d52Sotto 	int i, j, lastalloc, index = 0, fragsize;
5248dde8bb6Sotto 	int64_t physmem;
5258dde8bb6Sotto 
5266aaa4aabSotto 	spoofed = 0;
5276aaa4aabSotto 	for (i = 0;  i < MAXPARTITIONS; i++)
5286aaa4aabSotto 		if (i != RAW_PART && DL_GETPSIZE(&lp_org->d_partitions[i]) != 0)
5296aaa4aabSotto 			spoofed = 1;
5306aaa4aabSotto 
5318dde8bb6Sotto 	physmem = getphysmem() / lp_org->d_secsize;
53234ae4198Skrw 
53334ae4198Skrw 	/* How big is the OpenBSD portion of the disk?  */
5348dde8bb6Sotto 	find_bounds(lp_org);
535557f712bSkrw 
5368dde8bb6Sotto 	cylsecs = lp_org->d_secpercyl;
5378dde8bb6Sotto again:
5388dde8bb6Sotto 	lp = &label;
5393d98fc8cSkrw 	for (i=0; i<MAXPARTITIONS; i++) {
5403d98fc8cSkrw 		free(mountpoints[i]);
5413d98fc8cSkrw 		mountpoints[i] = NULL;
5423d98fc8cSkrw 	}
5438dde8bb6Sotto 	memcpy(lp, lp_org, sizeof(struct disklabel));
5440a7398ceSderaadt 	lp->d_npartitions = MAXPARTITIONS;
5458dde8bb6Sotto 	lastalloc = alloc_table[index].sz;
5468dde8bb6Sotto 	alloc = malloc(lastalloc * sizeof(struct space_allocation));
5478dde8bb6Sotto 	if (alloc == NULL)
5488dde8bb6Sotto 		errx(4, "out of memory");
5498dde8bb6Sotto 	memcpy(alloc, alloc_table[index].table,
5508dde8bb6Sotto 	    lastalloc * sizeof(struct space_allocation));
5518dde8bb6Sotto 
5528dde8bb6Sotto 	/* bump max swap based on phys mem, little physmem gets 2x swap */
5538dde8bb6Sotto 	if (index == 0) {
5548dde8bb6Sotto 		if (physmem < 256LL * 1024 * 1024 / lp->d_secsize)
5558dde8bb6Sotto 			alloc[1].maxsz = 2 * physmem;
5568dde8bb6Sotto 		else
5578dde8bb6Sotto 			alloc[1].maxsz += physmem;
5588dde8bb6Sotto 		/* bump max /var to make room for 2 crash dumps */
5598dde8bb6Sotto 		alloc[3].maxsz += 2 * physmem;
5608dde8bb6Sotto 	}
5618dde8bb6Sotto 
56234ae4198Skrw 	xtrasecs = totsecs = editor_countfree(lp);
563557f712bSkrw 
56434ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
5655f3e1104Skrw 		alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz);
5665f3e1104Skrw 		alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz);
56734ae4198Skrw 		if (xtrasecs > alloc[i].minsz)
56834ae4198Skrw 			xtrasecs -= alloc[i].minsz;
56934ae4198Skrw 		else
57034ae4198Skrw 			xtrasecs = 0;
571557f712bSkrw 	}
572557f712bSkrw 
57334ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
57434ae4198Skrw 		/* Find next available partition. */
57534ae4198Skrw 		for (j = 0;  j < MAXPARTITIONS; j++)
57634ae4198Skrw 			if (DL_GETPSIZE(&lp->d_partitions[j]) == 0)
57734ae4198Skrw 				break;
57834ae4198Skrw 		if (j == MAXPARTITIONS)
57934ae4198Skrw 			return;
58034ae4198Skrw 		pp = &lp->d_partitions[j];
58134ae4198Skrw 		partmp = &mountpoints[j];
58234ae4198Skrw 		ap = &alloc[i];
583557f712bSkrw 
58434ae4198Skrw 		/* Figure out the size of the partition. */
58534ae4198Skrw 		if (i == lastalloc - 1) {
58634ae4198Skrw 			if (totsecs > ap->maxsz)
58734ae4198Skrw 				secs = ap->maxsz;
588557f712bSkrw 			else
5895f3e1104Skrw 				secs = totsecs;
5901f5ea549Skrw #ifdef SUN_CYLCHECK
5911f5ea549Skrw 			goto cylinderalign;
5921f5ea549Skrw #endif
593557f712bSkrw 		} else {
59434ae4198Skrw 			secs = ap->minsz;
5955f3e1104Skrw 			if (xtrasecs > 0)
59634ae4198Skrw 				secs += (xtrasecs / 100) * ap->rate;
59734ae4198Skrw 			if (secs > ap->maxsz)
59834ae4198Skrw 				secs = ap->maxsz;
5991f5ea549Skrw #ifdef SUN_CYLCHECK
6001f5ea549Skrw cylinderalign:
6015f3e1104Skrw 			secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
6021f5ea549Skrw #endif
6035f3e1104Skrw 			totsecs -= secs;
6041f5ea549Skrw #ifdef SUN_CYLCHECK
6055f3e1104Skrw 			while (totsecs < 0) {
6065f3e1104Skrw 				secs -= cylsecs;
6075f3e1104Skrw 				totsecs += cylsecs;
608557f712bSkrw 			}
6091f5ea549Skrw #endif
610557f712bSkrw 		}
61134ae4198Skrw 
61234ae4198Skrw 		/* Find largest chunk of free space. */
61334ae4198Skrw 		chunks = free_chunks(lp);
61434ae4198Skrw 		chunkstart = 0;
61534ae4198Skrw 		chunksize = 0;
61634ae4198Skrw 		for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++)
61734ae4198Skrw 			if ((chunks[j].stop - chunks[j].start) > chunksize) {
61834ae4198Skrw 				chunkstart = chunks[j].start;
61934ae4198Skrw 				chunksize = chunks[j].stop - chunks[j].start;
620557f712bSkrw 			}
62134ae4198Skrw #ifdef SUN_CYLCHECK
62234ae4198Skrw 		if (lp->d_flags & D_VENDOR) {
62334ae4198Skrw 			/* Align chunk to cylinder boundaries. */
62434ae4198Skrw 			chunksize -= chunksize % cylsecs;
6256ab0bb66Skrw 			chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) *
6266ab0bb66Skrw 			    cylsecs;
62734ae4198Skrw 		}
62834ae4198Skrw #endif
62934ae4198Skrw 		/* See if partition can fit into chunk. */
63034ae4198Skrw 		if (secs > chunksize) {
63134ae4198Skrw 			totsecs += secs - chunksize;
63234ae4198Skrw 			secs = chunksize;
63334ae4198Skrw 		}
63434ae4198Skrw 		if (secs < ap->minsz) {
6358dde8bb6Sotto 			/* It did not work out, try next strategy */
6368dde8bb6Sotto 			free(alloc);
6378dde8bb6Sotto 			if (++index < nitems(alloc_table))
6388dde8bb6Sotto 				goto again;
6398dde8bb6Sotto 			else
6408dde8bb6Sotto 				return;
641557f712bSkrw 		}
64234ae4198Skrw 
64334ae4198Skrw 		/* Everything seems ok so configure the partition. */
6445f3e1104Skrw 		DL_SETPSIZE(pp, secs);
64534ae4198Skrw 		DL_SETPOFFSET(pp, chunkstart);
6466e312d52Sotto 		fragsize = 2048;
6476e312d52Sotto 		if (secs > 512ULL * 1024 * 1024 * 1024 / lp->d_secsize)
6486e312d52Sotto 			fragsize *= 4;
649557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__)
650557f712bSkrw 		/* can't boot from > 8k boot blocks */
651557f712bSkrw 		pp->p_fragblock =
6526e312d52Sotto 		    DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8);
653557f712bSkrw #else
6546e312d52Sotto 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
655557f712bSkrw #endif
656557f712bSkrw 		pp->p_cpg = 1;
65734ae4198Skrw 		if (ap->mp[0] != '/')
65834ae4198Skrw 			pp->p_fstype = FS_SWAP;
65934ae4198Skrw 		else {
66034ae4198Skrw 			pp->p_fstype = FS_BSDFFS;
66134ae4198Skrw 			free(*partmp);
66234ae4198Skrw 			if ((*partmp = strdup(ap->mp)) == NULL)
663557f712bSkrw 				errx(4, "out of memory");
664557f712bSkrw 		}
665557f712bSkrw 	}
666557f712bSkrw 
6678dde8bb6Sotto 	free(alloc);
6688dde8bb6Sotto 	memcpy(lp_org, lp, sizeof(struct disklabel));
669557f712bSkrw }
670557f712bSkrw 
671557f712bSkrw /*
6726aaa4aabSotto  * Resize a partition, moving all subsequent partitions
6736aaa4aabSotto  */
6746aaa4aabSotto void
6756aaa4aabSotto editor_resize(struct disklabel *lp, char *p)
6766aaa4aabSotto {
6776aaa4aabSotto 	struct disklabel label;
6786aaa4aabSotto 	struct partition *pp, *prev;
6796aaa4aabSotto 	daddr64_t secs, sz, off;
6806aaa4aabSotto #ifdef SUN_CYLCHECK
6816aaa4aabSotto 	daddr64_t cylsecs;
6826aaa4aabSotto #endif
6836aaa4aabSotto 	int partno, i;
6846aaa4aabSotto 
6856aaa4aabSotto 	label = *lp;
6866aaa4aabSotto 
6876aaa4aabSotto 	/* Change which partition? */
6886aaa4aabSotto 	if (p == NULL) {
6896aaa4aabSotto 		p = getstring("partition to resize",
6906aaa4aabSotto 		    "The letter of the partition to name, a - p.", NULL);
6916aaa4aabSotto 	}
6926aaa4aabSotto 	if (p == NULL) {
6936aaa4aabSotto 		fputs("Command aborted\n", stderr);
6946aaa4aabSotto 		return;
6956aaa4aabSotto 	}
6966aaa4aabSotto 	partno = p[0] - 'a';
6976aaa4aabSotto         if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
6986aaa4aabSotto 		fprintf(stderr, "Partition must be between 'a' and '%c' "
6996aaa4aabSotto 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
7006aaa4aabSotto 		return;
7016aaa4aabSotto 	}
7026aaa4aabSotto 
7036aaa4aabSotto 	pp = &label.d_partitions[partno];
7046aaa4aabSotto 	sz = editor_countfree(lp);
7056aaa4aabSotto 	secs = getuint(lp, "resize", "amount to grow (+) or shrink (-)",
7066aaa4aabSotto 	    0, sz, 0, DO_CONVERSIONS);
7076aaa4aabSotto 
7086aaa4aabSotto 	if (secs == 0) {
7096aaa4aabSotto 		fputs("Command aborted\n", stderr);
7106aaa4aabSotto 		return;
7116aaa4aabSotto 	}
7126aaa4aabSotto 
7136aaa4aabSotto #ifdef SUN_CYLCHECK
7146aaa4aabSotto 	cylsecs = lp->d_secpercyl;
7156aaa4aabSotto 	if (secs > 0)
7166aaa4aabSotto 		secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
7176aaa4aabSotto 	else
7186aaa4aabSotto 		secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs;
7196aaa4aabSotto #endif
7206aaa4aabSotto 
7216aaa4aabSotto 	sz = DL_GETPSIZE(pp);
7226aaa4aabSotto 	if (sz == 0) {
7236aaa4aabSotto 		fputs("No such parititon\n", stderr);
7246aaa4aabSotto 		return;
7256aaa4aabSotto 	}
7266aaa4aabSotto 	if (DL_GETPOFFSET(pp) + sz + secs > ending_sector) {
7276aaa4aabSotto 		fputs("Amount too big\n", stderr);
7286aaa4aabSotto 		return;
7296aaa4aabSotto 	}
7306aaa4aabSotto 	if (sz + secs < 0) {
7316aaa4aabSotto 		fputs("Amount too small\n", stderr);
7326aaa4aabSotto 		return;
7336aaa4aabSotto 	}
7346aaa4aabSotto 
7356aaa4aabSotto 	DL_SETPSIZE(pp, sz + secs);
7366aaa4aabSotto 
7376aaa4aabSotto 	/*
7386aaa4aabSotto 	 * Pack partitions above the resized partition, leaving unused
7396aaa4aabSotto 	 * partions alone.
7406aaa4aabSotto 	 */
7416aaa4aabSotto 	prev = pp;
7426aaa4aabSotto 	for (i = partno + 1; i < MAXPARTITIONS; i++) {
7436aaa4aabSotto 		if (i == RAW_PART)
7446aaa4aabSotto 			continue;
7456aaa4aabSotto 		sz = DL_GETPSIZE(&label.d_partitions[i]);
7466aaa4aabSotto 		if (sz == 0)
7476aaa4aabSotto 			continue;
7486aaa4aabSotto 
7496aaa4aabSotto 		pp = &label.d_partitions[i];
7506aaa4aabSotto 		off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
7516aaa4aabSotto 
7526aaa4aabSotto 		if (off < ending_sector) {
7536aaa4aabSotto 			DL_SETPOFFSET(pp, off);
7546aaa4aabSotto 			if (off + DL_GETPSIZE(pp) > ending_sector) {
7556aaa4aabSotto 				DL_SETPSIZE(pp, ending_sector - off);
7566aaa4aabSotto 				fprintf(stderr,
7576aaa4aabSotto 				    "Partition %c shrunk to make room\n",
7586aaa4aabSotto 				    i + 'a');
7596aaa4aabSotto 			}
7606aaa4aabSotto 		} else {
7616aaa4aabSotto 			fputs("No room left for all partitions\n", stderr);
7626aaa4aabSotto 			return;
7636aaa4aabSotto 		}
7646aaa4aabSotto 		prev = pp;
7656aaa4aabSotto 	}
7666aaa4aabSotto 	*lp = label;
7676aaa4aabSotto }
7686aaa4aabSotto 
7696aaa4aabSotto /*
7706fe57b42Smillert  * Add a new partition.
7716fe57b42Smillert  */
7726fe57b42Smillert void
77334ae4198Skrw editor_add(struct disklabel *lp, char *p)
7746fe57b42Smillert {
77596a888c6Smillert 	struct partition *pp;
77696a888c6Smillert 	struct diskchunk *chunks;
7775caa08b2Skrw 	char buf[2];
7786e312d52Sotto 	int i, partno, fragsize;
779f8ab7229Schl 	u_int64_t freesectors, new_offset, new_size;
7809fdcb4d6Skrw 
7819fdcb4d6Skrw 	freesectors = editor_countfree(lp);
7826fe57b42Smillert 
7836fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
784fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
7859fdcb4d6Skrw 	if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) {
786fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
787fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
788fc1a4cc6Sderaadt 		    stderr);
789fc1a4cc6Sderaadt 		return;
790fc1a4cc6Sderaadt 	}
7918390cf28Smillert #endif
7929fdcb4d6Skrw 	if (freesectors == 0) {
7936fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
7946fe57b42Smillert 		    stderr);
7956fe57b42Smillert 		return;
7966fe57b42Smillert 	}
7976fe57b42Smillert 
7985caa08b2Skrw 	if (p == NULL) {
7995caa08b2Skrw 		/*
8005caa08b2Skrw 		 * Use the first unused partition that is not 'c' as the
8015caa08b2Skrw 		 * default partition in the prompt string.
8025caa08b2Skrw 		 */
8035caa08b2Skrw 		pp = &lp->d_partitions[0];
8045caa08b2Skrw 		buf[0] = buf[1] = '\0';
8055caa08b2Skrw 		for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) {
8065caa08b2Skrw 			if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) {
8075caa08b2Skrw 				buf[0] = partno + 'a';
8085caa08b2Skrw 				p = &buf[0];
8096fe57b42Smillert 				break;
8106fe57b42Smillert 			}
8115caa08b2Skrw 		}
812c33fcabaSmillert 		p = getstring("partition",
8136fe57b42Smillert 		    "The letter of the new partition, a - p.", p);
8146fe57b42Smillert 	}
8155caa08b2Skrw 	if (p == NULL) {
8165caa08b2Skrw 		fputs("Command aborted\n", stderr);
8175caa08b2Skrw 		return;
8185caa08b2Skrw 	}
8195caa08b2Skrw 	partno = p[0] - 'a';
8205caa08b2Skrw 	if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) {
8215caa08b2Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
8225caa08b2Skrw 		    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
8235caa08b2Skrw 		return;
8245caa08b2Skrw 	}
8255caa08b2Skrw 	pp = &lp->d_partitions[partno];
8265caa08b2Skrw 
8275caa08b2Skrw 	if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) {
8285caa08b2Skrw 		fprintf(stderr, "Partition '%c' exists.  Delete it first.\n",
8295caa08b2Skrw 		    p[0]);
8305caa08b2Skrw 		return;
8316fe57b42Smillert 	}
83296a888c6Smillert 
833caf41f96Skrw 	/*
834caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
835855d4e83Ssobrado 	 * zero'ed to avoid inadvertent overlaps.
836caf41f96Skrw 	 */
837caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
838caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
83996a888c6Smillert 
84089f4601dSkrw 	/* Make sure selected partition is zero'd too. */
84189f4601dSkrw 	memset(pp, 0, sizeof(*pp));
84215c15d8aSkrw 	chunks = free_chunks(lp);
84315c15d8aSkrw 
84415c15d8aSkrw 	/*
84515c15d8aSkrw 	 * Since we know there's free space, there must be at least one
84615c15d8aSkrw 	 * chunk. So find the largest chunk and assume we want to add the
84715c15d8aSkrw 	 * partition in that free space.
84815c15d8aSkrw 	 */
84915c15d8aSkrw 	new_size = new_offset = 0;
85015c15d8aSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
85115c15d8aSkrw 		if (chunks[i].stop - chunks[i].start > new_size) {
85215c15d8aSkrw 		    new_size = chunks[i].stop - chunks[i].start;
85315c15d8aSkrw 		    new_offset = chunks[i].start;
85415c15d8aSkrw 		}
85515c15d8aSkrw 	}
8561e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
8571e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
85896a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
8596e312d52Sotto 	fragsize = 2048;
8606e312d52Sotto 	if (new_size > 512ULL * 1024 * 1024 * 1024 / lp->d_secsize)
8616e312d52Sotto 		fragsize *= 4;
8624a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__)
863d98d4df7Stedu 	/* can't boot from > 8k boot blocks */
864ddfcbf38Sotto 	pp->p_fragblock =
8656e312d52Sotto 	    DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8);
866d98d4df7Stedu #else
8676e312d52Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
868d98d4df7Stedu #endif
8699b972314Skrw 	pp->p_cpg = 1;
87096a888c6Smillert 
871a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
872a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
873a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
87434ae4198Skrw 	    get_mp(lp, partno) == 0 &&
875a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
876a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
87796a888c6Smillert 		return;
87896a888c6Smillert 
879a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
880a4c87e64Skrw 	DL_SETPSIZE(pp, 0);
8816fe57b42Smillert }
8826fe57b42Smillert 
8836fe57b42Smillert /*
884bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
885bd6726faSmillert  */
886bd6726faSmillert void
88734ae4198Skrw editor_name(struct disklabel *lp, char *p)
888bd6726faSmillert {
889bd6726faSmillert 	struct partition *pp;
890bd6726faSmillert 	int partno;
891bd6726faSmillert 
892bd6726faSmillert 	/* Change which partition? */
893bd6726faSmillert 	if (p == NULL) {
894c33fcabaSmillert 		p = getstring("partition to name",
895bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
896bd6726faSmillert 	}
897bd6726faSmillert 	if (p == NULL) {
898bd6726faSmillert 		fputs("Command aborted\n", stderr);
899bd6726faSmillert 		return;
900bd6726faSmillert 	}
901bd6726faSmillert 	partno = p[0] - 'a';
9026c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9036c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9046c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
905bd6726faSmillert 		return;
90666df1f0cSkrw 	}
90766df1f0cSkrw 	pp = &lp->d_partitions[partno];
90866df1f0cSkrw 
90966df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
91066df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
911bd6726faSmillert 		return;
912bd6726faSmillert 	}
913bd6726faSmillert 
914bd6726faSmillert 	/* Not all fstypes can be named */
915bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
916bd387921Stodd 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER ||
917bd387921Stodd 	    pp->p_fstype == FS_RAID) {
918bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
919baa55472Smillert 		    fstypenames[lp->d_partitions[partno].p_fstype]);
920bd6726faSmillert 		return;
921bd6726faSmillert 	}
922bd6726faSmillert 
92334ae4198Skrw 	get_mp(lp, partno);
924bd6726faSmillert }
925bd6726faSmillert 
926bd6726faSmillert /*
9276fe57b42Smillert  * Change an existing partition.
9286fe57b42Smillert  */
9296fe57b42Smillert void
93034ae4198Skrw editor_modify(struct disklabel *lp, char *p)
9316fe57b42Smillert {
9326fe57b42Smillert 	struct partition origpart, *pp;
933f8ab7229Schl 	int partno;
9346fe57b42Smillert 
9356fe57b42Smillert 	/* Change which partition? */
9366fe57b42Smillert 	if (p == NULL) {
937c33fcabaSmillert 		p = getstring("partition to modify",
9386fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
9396fe57b42Smillert 	}
94096a888c6Smillert 	if (p == NULL) {
94196a888c6Smillert 		fputs("Command aborted\n", stderr);
94296a888c6Smillert 		return;
94396a888c6Smillert 	}
9446fe57b42Smillert 	partno = p[0] - 'a';
9456c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9466c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9476c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
9486fe57b42Smillert 		return;
94966df1f0cSkrw 	}
95066df1f0cSkrw 	pp = &lp->d_partitions[partno];
95166df1f0cSkrw 
95266df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
95366df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
9546fe57b42Smillert 		return;
9556fe57b42Smillert 	}
9566fe57b42Smillert 
95766df1f0cSkrw 	origpart = *pp;
95866df1f0cSkrw 
959a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
960a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
961a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
96234ae4198Skrw 	    get_mp(lp, partno) == 0 &&
963a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
964a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
96596a888c6Smillert 		return;
9666fe57b42Smillert 
967a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
968a4c87e64Skrw 	*pp = origpart;
9696fe57b42Smillert }
9706fe57b42Smillert 
9716fe57b42Smillert /*
9726fe57b42Smillert  * Delete an existing partition.
9736fe57b42Smillert  */
9746fe57b42Smillert void
97534ae4198Skrw editor_delete(struct disklabel *lp, char *p)
9766fe57b42Smillert {
97766df1f0cSkrw 	struct partition *pp;
978135c90d1Skrw 	int partno;
9796fe57b42Smillert 
9806fe57b42Smillert 	if (p == NULL) {
981c33fcabaSmillert 		p = getstring("partition to delete",
982945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
983945ae268Smillert 		    NULL);
9846fe57b42Smillert 	}
98596a888c6Smillert 	if (p == NULL) {
98696a888c6Smillert 		fputs("Command aborted\n", stderr);
98796a888c6Smillert 		return;
98896a888c6Smillert 	}
989945ae268Smillert 	if (p[0] == '*') {
9909fdcb4d6Skrw 		zero_partitions(lp);
991945ae268Smillert 		return;
992945ae268Smillert 	}
993135c90d1Skrw 	partno = p[0] - 'a';
994135c90d1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9956c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9966c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
99733262abfSmiod 		return;
99866df1f0cSkrw 	}
999135c90d1Skrw 	pp = &lp->d_partitions[partno];
100066df1f0cSkrw 
100166df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
100266df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
100333262abfSmiod 		return;
100466df1f0cSkrw 	}
100566df1f0cSkrw 
10066fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
1007135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
100834ae4198Skrw 	free(mountpoints[partno]);
100934ae4198Skrw 	mountpoints[partno] = NULL;
10106fe57b42Smillert }
10116fe57b42Smillert 
10126fe57b42Smillert /*
10136fe57b42Smillert  * Change the size of an existing partition.
10146fe57b42Smillert  */
10156fe57b42Smillert void
10169fdcb4d6Skrw editor_change(struct disklabel *lp, char *p)
10176fe57b42Smillert {
10184b9a3bdaSmillert 	struct partition *pp;
101966df1f0cSkrw 	int partno;
10206fe57b42Smillert 
10216fe57b42Smillert 	if (p == NULL) {
1022c33fcabaSmillert 		p = getstring("partition to change size",
10236fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
10246fe57b42Smillert 	}
102596a888c6Smillert 	if (p == NULL) {
102696a888c6Smillert 		fputs("Command aborted\n", stderr);
102796a888c6Smillert 		return;
102896a888c6Smillert 	}
10296fe57b42Smillert 	partno = p[0] - 'a';
10306c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10316c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10326c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
10336fe57b42Smillert 		return;
10346fe57b42Smillert 	}
10354b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
10366fe57b42Smillert 
103766df1f0cSkrw 	if (DL_GETPSIZE(pp) == 0) {
103866df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
103966df1f0cSkrw 		return;
104066df1f0cSkrw 	}
104166df1f0cSkrw 
104214192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
104314192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
104414192793Skrw 	    p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno));
10457da73705Skrw 
104659ccf790Skrw 	/* Get new size */
10479fdcb4d6Skrw 	get_size(lp, partno);
10486fe57b42Smillert }
10496fe57b42Smillert 
10506fe57b42Smillert /*
10516fe57b42Smillert  * Sort the partitions based on starting offset.
10526fe57b42Smillert  * This assumes there can be no overlap.
10536fe57b42Smillert  */
10546fe57b42Smillert int
10558809fabbSderaadt partition_cmp(const void *e1, const void *e2)
10566fe57b42Smillert {
10576fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10586fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10591e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
10601e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
10616fe57b42Smillert 
10621e0ad43cSotto 	if (o1 < o2)
1063651d5bd9Sotto 		return -1;
10641e0ad43cSotto 	else if (o1 > o2)
1065651d5bd9Sotto 		return 1;
1066651d5bd9Sotto 	else
1067651d5bd9Sotto 		return 0;
10686fe57b42Smillert }
10696fe57b42Smillert 
10706fe57b42Smillert char *
10718809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval)
10726fe57b42Smillert {
10736fe57b42Smillert 	static char buf[BUFSIZ];
10746fe57b42Smillert 	int n;
10756fe57b42Smillert 
10766fe57b42Smillert 	buf[0] = '\0';
10776fe57b42Smillert 	do {
10786fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
10796e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1080260513deSmillert 			buf[0] = '\0';
108196a888c6Smillert 			if (feof(stdin)) {
108224c6582eSmillert 				clearerr(stdin);
108396a888c6Smillert 				putchar('\n');
108496a888c6Smillert 				return(NULL);
108596a888c6Smillert 			}
10866e0becc5Smillert 		}
10876fe57b42Smillert 		n = strlen(buf);
10886fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
10896fe57b42Smillert 			buf[--n] = '\0';
10906fe57b42Smillert 		if (buf[0] == '?')
10916fe57b42Smillert 			puts(helpstring);
10924fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
10934fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
10946fe57b42Smillert 	} while (buf[0] == '?');
10956fe57b42Smillert 
10966fe57b42Smillert 	return(&buf[0]);
10976fe57b42Smillert }
10986fe57b42Smillert 
10996fe57b42Smillert /*
11001e0ad43cSotto  * Returns ULLONG_MAX on error
110124a2c1a4Smillert  * Usually only called by helper functions.
11026fe57b42Smillert  */
11031e0ad43cSotto u_int64_t
1104dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring,
11051e0ad43cSotto     u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags)
11066fe57b42Smillert {
11076fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
11081e0ad43cSotto 	u_int64_t rval = oval;
11096fe57b42Smillert 	size_t n;
11106fe57b42Smillert 	int mult = 1;
111114cc915fSmillert 	double d, percent = 1.0;
11126fe57b42Smillert 
11134b9a3bdaSmillert 	/* We only care about the remainder */
11144b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
11154b9a3bdaSmillert 
11166fe57b42Smillert 	buf[0] = '\0';
11176fe57b42Smillert 	do {
11181e0ad43cSotto 		printf("%s: [%llu] ", prompt, oval);
11196e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11206e0becc5Smillert 			buf[0] = '\0';
112196a888c6Smillert 			if (feof(stdin)) {
112224c6582eSmillert 				clearerr(stdin);
112396a888c6Smillert 				putchar('\n');
11241e0ad43cSotto 				return(ULLONG_MAX - 1);
112596a888c6Smillert 			}
11266e0becc5Smillert 		}
11276fe57b42Smillert 		n = strlen(buf);
11286fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11296fe57b42Smillert 			buf[--n] = '\0';
11306fe57b42Smillert 		if (buf[0] == '?')
11316fe57b42Smillert 			puts(helpstring);
11326fe57b42Smillert 	} while (buf[0] == '?');
11336fe57b42Smillert 
11346fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11356fe57b42Smillert 		rval = maxval;
11366fe57b42Smillert 	} else {
11376fe57b42Smillert 		/* deal with units */
11386fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11396fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
114096a888c6Smillert 				switch (tolower(buf[n-1])) {
11416fe57b42Smillert 
11426fe57b42Smillert 				case 'c':
11436fe57b42Smillert 					mult = lp->d_secpercyl;
11446fe57b42Smillert 					buf[--n] = '\0';
11456fe57b42Smillert 					break;
11466fe57b42Smillert 				case 'b':
11476fe57b42Smillert 					mult = -lp->d_secsize;
11486fe57b42Smillert 					buf[--n] = '\0';
11496fe57b42Smillert 					break;
11506fe57b42Smillert 				case 'k':
115150c0f47aSkrw 					if (lp->d_secsize > 1024)
115250c0f47aSkrw 						mult = -lp->d_secsize / 1024;
115350c0f47aSkrw 					else
11546fe57b42Smillert 						mult = 1024 / lp->d_secsize;
11556fe57b42Smillert 					buf[--n] = '\0';
11566fe57b42Smillert 					break;
11576fe57b42Smillert 				case 'm':
11586fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
11596fe57b42Smillert 					buf[--n] = '\0';
11606fe57b42Smillert 					break;
11611a51a1eeSmillert 				case 'g':
11621a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
11631a51a1eeSmillert 					buf[--n] = '\0';
11641a51a1eeSmillert 					break;
116514cc915fSmillert 				case '%':
116614cc915fSmillert 					buf[--n] = '\0';
116714cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
11681e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
11691e0ad43cSotto 					    DL_GETDSIZE(lp));
117014cc915fSmillert 					break;
117114cc915fSmillert 				case '&':
117214cc915fSmillert 					buf[--n] = '\0';
117314cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
11741e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
117514cc915fSmillert 					    maxval);
117614cc915fSmillert 					break;
11776fe57b42Smillert 				}
117896a888c6Smillert 			}
11796fe57b42Smillert 
11806fe57b42Smillert 			/* Did they give us an operator? */
11816fe57b42Smillert 			p = &buf[0];
11826fe57b42Smillert 			if (*p == '+' || *p == '-')
11836fe57b42Smillert 				operator = *p++;
11846fe57b42Smillert 
11856fe57b42Smillert 			endptr = p;
118696a888c6Smillert 			errno = 0;
118796a888c6Smillert 			d = strtod(p, &endptr);
118896a888c6Smillert 			if (errno == ERANGE)
11891e0ad43cSotto 				rval = ULLONG_MAX;	/* too big/small */
119096a888c6Smillert 			else if (*endptr != '\0') {
11916fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
11921e0ad43cSotto 				rval = ULLONG_MAX;
11936fe57b42Smillert 			} else {
119496a888c6Smillert 				/* XXX - should check for overflow */
119596a888c6Smillert 				if (mult > 0)
119614cc915fSmillert 					rval = d * mult * percent;
119796a888c6Smillert 				else
119896a888c6Smillert 					/* Negative mult means divide (fancy) */
119914cc915fSmillert 					rval = d / (-mult) * percent;
12006fe57b42Smillert 
120196a888c6Smillert 				/* Apply the operator */
12026fe57b42Smillert 				if (operator == '+')
12036fe57b42Smillert 					rval += oval;
12046fe57b42Smillert 				else if (operator == '-')
12056fe57b42Smillert 					rval = oval - rval;
12066fe57b42Smillert 			}
12076fe57b42Smillert 		}
12086fe57b42Smillert 	}
12098390cf28Smillert 	if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) {
121096a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
12118390cf28Smillert 		if (
1212fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
1213fc1a4cc6Sderaadt 		    ((lp->d_flags & D_VENDOR) || mult != 1) &&
1214fc1a4cc6Sderaadt #else
12158390cf28Smillert 		    mult != 1 &&
1216dbffb156Smillert #endif
12178390cf28Smillert 		    (rval + offset) % lp->d_secpercyl != 0) {
12181e0ad43cSotto 			u_int64_t cyls;
1219dbffb156Smillert 
12208390cf28Smillert 			/* Round to higher cylinder but no more than maxval */
12218390cf28Smillert 			cyls = (rval / lp->d_secpercyl) + 1;
12228390cf28Smillert 			if ((cyls * lp->d_secpercyl) - offset > maxval)
1223dbffb156Smillert 				cyls--;
12244b9a3bdaSmillert 			rval = (cyls * lp->d_secpercyl) - offset;
12258390cf28Smillert 			printf("Rounding to cylinder: %llu\n", rval);
12266fe57b42Smillert 		}
12274b9a3bdaSmillert 	}
12286fe57b42Smillert 
12296fe57b42Smillert 	return(rval);
12306fe57b42Smillert }
12316fe57b42Smillert 
12326fe57b42Smillert /*
12331f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
12341f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
12356fe57b42Smillert  */
12366fe57b42Smillert int
12371f0f871dSkrw has_overlap(struct disklabel *lp)
12386fe57b42Smillert {
12396fe57b42Smillert 	struct partition **spp;
1240e6aa8bafSmillert 	int c, i, j;
1241e6aa8bafSmillert 	char buf[BUFSIZ];
12426fe57b42Smillert 
12430fbd3c97Skrw 	/* Get a sorted list of the in-use partitions. */
12440fbd3c97Skrw 	spp = sort_partitions(lp);
12456fe57b42Smillert 
12460fbd3c97Skrw 	/* If there are less than two partitions in use, there is no overlap. */
12470fbd3c97Skrw 	if (spp[1] == NULL)
12480fbd3c97Skrw 		return(0);
12496fe57b42Smillert 
12506fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12510fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
12520fbd3c97Skrw 		for (j = i + 1; spp[j] != NULL; j++) {
12536fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
12541e0ad43cSotto 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) {
12556fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
12566fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
12576fe57b42Smillert 				    / sizeof(**spp);
12586fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
12596fe57b42Smillert 				    / sizeof(**spp);
12606fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
12616fe57b42Smillert 				    'a' + i, 'a' + j);
1262366bf641Skrw 				printf("#    %16.16s %16.16s  fstype "
1263651d5bd9Sotto 				    "[fsize bsize  cpg]\n", "size", "offset");
126434ae4198Skrw 				display_partition(stdout, lp, i, 0);
126534ae4198Skrw 				display_partition(stdout, lp, j, 0);
12666fe57b42Smillert 
1267e6aa8bafSmillert 				/* Get partition to disable or ^D */
1268e6aa8bafSmillert 				do {
1269616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
12706fe57b42Smillert 					    'a' + i, 'a' + j);
1271e6aa8bafSmillert 					buf[0] = '\0';
1272616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1273616cd1c4Smillert 						putchar('\n');
1274e6aa8bafSmillert 						return(1);	/* ^D */
1275616cd1c4Smillert 					}
1276e6aa8bafSmillert 					c = buf[0] - 'a';
1277e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1278e6aa8bafSmillert 				    c != i && c != j);
1279e6aa8bafSmillert 
1280e6aa8bafSmillert 				/* Mark the selected one as unused */
12816fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
12821f0f871dSkrw 				return (has_overlap(lp));
12836fe57b42Smillert 			}
12846fe57b42Smillert 		}
12856fe57b42Smillert 	}
1286f0b4d0a9Smillert 
1287e6aa8bafSmillert 	return(0);
12886fe57b42Smillert }
12896fe57b42Smillert 
12906fe57b42Smillert void
12919fdcb4d6Skrw edit_parms(struct disklabel *lp)
12926fe57b42Smillert {
12936fe57b42Smillert 	char *p;
12949fdcb4d6Skrw 	u_int64_t freesectors, ui;
129596a888c6Smillert 	struct disklabel oldlabel = *lp;
12966fe57b42Smillert 
1297ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
12986fe57b42Smillert 
12990f820bbbSmillert 	/* disk type */
13000f820bbbSmillert 	for (;;) {
1301c33fcabaSmillert 		p = getstring("disk type",
130241282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
130341282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
130496a888c6Smillert 		if (p == NULL) {
130596a888c6Smillert 			fputs("Command aborted\n", stderr);
130696a888c6Smillert 			return;
130796a888c6Smillert 		}
130841282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
130941282a2aSmillert 			ui = DTYPE_ESDI;
131041282a2aSmillert 		else
131141282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
131241282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13130f820bbbSmillert 				;
13140f820bbbSmillert 		if (ui < DKMAXTYPES) {
13150f820bbbSmillert 			break;
13160f820bbbSmillert 		} else {
13170f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13180f820bbbSmillert 			fputs("Valid types are: ", stdout);
13190f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13200f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13210f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13220f820bbbSmillert 					fputs(", ", stdout);
13230f820bbbSmillert 			}
13240f820bbbSmillert 			putchar('\n');
13250f820bbbSmillert 		}
13260f820bbbSmillert 	}
13270f820bbbSmillert 	lp->d_type = ui;
13280f820bbbSmillert 
13296fe57b42Smillert 	/* pack/label id */
1330c33fcabaSmillert 	p = getstring("label name",
13316fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13326fe57b42Smillert 	    lp->d_packname);
133396a888c6Smillert 	if (p == NULL) {
133496a888c6Smillert 		fputs("Command aborted\n", stderr);
133596a888c6Smillert 		*lp = oldlabel;		/* undo damage */
133696a888c6Smillert 		return;
133796a888c6Smillert 	}
13384fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
13396fe57b42Smillert 
13406fe57b42Smillert 	/* sectors/track */
13416fe57b42Smillert 	for (;;) {
1342dea75673Skrw 		ui = getuint(lp, "sectors/track",
1343cfd24250Skrw 		    "The Number of sectors per track.", lp->d_nsectors,
13444b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
13451e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
134696a888c6Smillert 			fputs("Command aborted\n", stderr);
134796a888c6Smillert 			*lp = oldlabel;		/* undo damage */
134896a888c6Smillert 			return;
13491e0ad43cSotto 		} if (ui == ULLONG_MAX)
13506fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13516fe57b42Smillert 		else
13526fe57b42Smillert 			break;
13536fe57b42Smillert 	}
13546fe57b42Smillert 	lp->d_nsectors = ui;
13556fe57b42Smillert 
13566fe57b42Smillert 	/* tracks/cylinder */
13576fe57b42Smillert 	for (;;) {
1358dea75673Skrw 		ui = getuint(lp, "tracks/cylinder",
13596fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
13604b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
13611e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
136296a888c6Smillert 			fputs("Command aborted\n", stderr);
136396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
136496a888c6Smillert 			return;
13651e0ad43cSotto 		} else if (ui == ULLONG_MAX)
13666fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13676fe57b42Smillert 		else
13686fe57b42Smillert 			break;
13696fe57b42Smillert 	}
13706fe57b42Smillert 	lp->d_ntracks = ui;
13716fe57b42Smillert 
13726fe57b42Smillert 	/* sectors/cylinder */
1373148b6188Smillert 	for (;;) {
1374dea75673Skrw 		ui = getuint(lp, "sectors/cylinder",
1375148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
13764b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
13774b9a3bdaSmillert 		    0, 0);
13781e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
137996a888c6Smillert 			fputs("Command aborted\n", stderr);
138096a888c6Smillert 			*lp = oldlabel;		/* undo damage */
138196a888c6Smillert 			return;
13821e0ad43cSotto 		} else if (ui == ULLONG_MAX)
1383148b6188Smillert 			fputs("Invalid entry\n", stderr);
1384148b6188Smillert 		else
1385148b6188Smillert 			break;
1386148b6188Smillert 	}
1387148b6188Smillert 	lp->d_secpercyl = ui;
13886fe57b42Smillert 
13896fe57b42Smillert 	/* number of cylinders */
13906fe57b42Smillert 	for (;;) {
1391dea75673Skrw 		ui = getuint(lp, "number of cylinders",
13926fe57b42Smillert 		    "The total number of cylinders on the disk.",
13934b9a3bdaSmillert 		    lp->d_ncylinders, lp->d_ncylinders, 0, 0);
13941e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
139596a888c6Smillert 			fputs("Command aborted\n", stderr);
139696a888c6Smillert 			*lp = oldlabel;		/* undo damage */
139796a888c6Smillert 			return;
13981e0ad43cSotto 		} else if (ui == ULLONG_MAX)
13996fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14006fe57b42Smillert 		else
14016fe57b42Smillert 			break;
14026fe57b42Smillert 	}
14036fe57b42Smillert 	lp->d_ncylinders = ui;
14046fe57b42Smillert 
14056fe57b42Smillert 	/* total sectors */
14066fe57b42Smillert 	for (;;) {
140734af67a3Sotto 		u_int64_t nsec = MAX(DL_GETDSIZE(lp),
140834af67a3Sotto 		    (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
1409dea75673Skrw 		ui = getuint(lp, "total sectors",
14106fe57b42Smillert 		    "The total number of sectors on the disk.",
1411baaa8969Smillert 		    nsec, nsec, 0, 0);
14121e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
141396a888c6Smillert 			fputs("Command aborted\n", stderr);
141496a888c6Smillert 			*lp = oldlabel;		/* undo damage */
141596a888c6Smillert 			return;
14161e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14176fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14181e0ad43cSotto 		else if (ui > DL_GETDSIZE(lp) &&
14191e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
1420f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1421f98aebd4Smillert 			    "partition.");
14226fe57b42Smillert 			break;
14231e0ad43cSotto 		} else if (ui < DL_GETDSIZE(lp) &&
14241e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
14256fe57b42Smillert 			/* shrink free count */
14269fdcb4d6Skrw 			freesectors = editor_countfree(lp);
14279fdcb4d6Skrw 			if (DL_GETDSIZE(lp) - ui > freesectors)
14286fe57b42Smillert 				fprintf(stderr,
14291e0ad43cSotto 				    "Not enough free space to shrink by %llu "
14301e0ad43cSotto 				    "sectors (only %llu sectors left)\n",
14319fdcb4d6Skrw 				    DL_GETDSIZE(lp) - ui, freesectors);
1432c4f83f03Skrw 			else
14336fe57b42Smillert 				break;
14346fe57b42Smillert 		} else
14356fe57b42Smillert 			break;
14366fe57b42Smillert 	}
143741ed49b7Smillert 	/* Adjust ending_sector if necessary. */
143896a888c6Smillert 	if (ending_sector > ui)
143996a888c6Smillert 		ending_sector = ui;
14401e0ad43cSotto 	DL_SETDSIZE(lp, ui);
14416fe57b42Smillert 
14426fe57b42Smillert 	/* rpm */
14436fe57b42Smillert 	for (;;) {
1444dea75673Skrw 		ui = getuint(lp, "rpm",
1445a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
14464b9a3bdaSmillert 		  lp->d_rpm, lp->d_rpm, 0, 0);
14471e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
144896a888c6Smillert 			fputs("Command aborted\n", stderr);
144996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
145096a888c6Smillert 			return;
14511e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14526fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14536fe57b42Smillert 		else
14546fe57b42Smillert 			break;
14556fe57b42Smillert 	}
14566fe57b42Smillert 	lp->d_rpm = ui;
1457440b1d70Smillert 
1458440b1d70Smillert 	/* interleave */
1459440b1d70Smillert 	for (;;) {
1460dea75673Skrw 		ui = getuint(lp, "interleave",
1461440b1d70Smillert 		  "The physical sector interleave, set when formatting.  Almost always 1.",
14624b9a3bdaSmillert 		  lp->d_interleave, lp->d_interleave, 0, 0);
14631e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
1464440b1d70Smillert 			fputs("Command aborted\n", stderr);
1465440b1d70Smillert 			*lp = oldlabel;		/* undo damage */
1466440b1d70Smillert 			return;
14671e0ad43cSotto 		} else if (ui == ULLONG_MAX || ui == 0)
1468440b1d70Smillert 			fputs("Invalid entry\n", stderr);
1469440b1d70Smillert 		else
1470440b1d70Smillert 			break;
1471440b1d70Smillert 	}
1472440b1d70Smillert 	lp->d_interleave = ui;
14736fe57b42Smillert }
1474a7e61405Smillert 
1475a7e61405Smillert struct partition **
14760fbd3c97Skrw sort_partitions(struct disklabel *lp)
1477a7e61405Smillert {
1478d18c2a43Skrw 	static struct partition *spp[MAXPARTITIONS+2];
14790fbd3c97Skrw 	int i, npartitions;
1480a7e61405Smillert 
1481d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1482d18c2a43Skrw 
1483a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1484a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1485a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
14861e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1487a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1488a7e61405Smillert 	}
1489a7e61405Smillert 
1490a7e61405Smillert 	/*
1491a7e61405Smillert 	 * Sort the partitions based on starting offset.
1492a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1493a7e61405Smillert 	 */
1494a7e61405Smillert 	if (npartitions > 1)
1495a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1496a7e61405Smillert 		    partition_cmp))
1497a7e61405Smillert 			err(4, "failed to sort partition table");
1498a7e61405Smillert 
1499a7e61405Smillert 	return(spp);
1500a7e61405Smillert }
15010f820bbbSmillert 
15020f820bbbSmillert /*
15030f820bbbSmillert  * Get a valid disk type if necessary.
15040f820bbbSmillert  */
15050f820bbbSmillert void
15068809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev)
15070f820bbbSmillert {
15080f820bbbSmillert 	int i;
1509803ff7d5Smillert 	char *s, *def = "SCSI";
1510803ff7d5Smillert 	struct dtypes {
1511803ff7d5Smillert 		char *dev;
1512803ff7d5Smillert 		char *type;
1513803ff7d5Smillert 	} dtypes[] = {
1514c33fcabaSmillert 		{ "sd",   "SCSI" },
1515c33fcabaSmillert 		{ "rz",   "SCSI" },
1516c33fcabaSmillert 		{ "wd",   "IDE" },
1517c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1518c33fcabaSmillert 		{ "xd",   "SMD" },
1519c33fcabaSmillert 		{ "xy",   "SMD" },
1520c33fcabaSmillert 		{ "hd",   "HP-IB" },
1521c33fcabaSmillert 		{ "ccd",  "CCD" },
1522c33fcabaSmillert 		{ "vnd",  "VND" },
1523c33fcabaSmillert 		{ "svnd", "VND" },
1524c33fcabaSmillert 		{ NULL,   NULL }
1525803ff7d5Smillert 	};
1526803ff7d5Smillert 
1527803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1528803ff7d5Smillert 		if (*s == 'r')
1529803ff7d5Smillert 			s++;
1530803ff7d5Smillert 		i = strcspn(s, "0123456789");
1531803ff7d5Smillert 		s[i] = '\0';
1532803ff7d5Smillert 		dev = s;
1533803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1534803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1535803ff7d5Smillert 				def = dtypes[i].type;
1536803ff7d5Smillert 				break;
1537803ff7d5Smillert 			}
1538803ff7d5Smillert 		}
1539803ff7d5Smillert 	}
15400f820bbbSmillert 
15410f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15420f820bbbSmillert 		puts(banner);
15430f820bbbSmillert 		puts("Possible values are:");
1544eb5dd924Sderaadt 		printf("\"IDE\", ");
15450f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15460f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15470f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15480f820bbbSmillert 				fputs(", ", stdout);
15490f820bbbSmillert 		}
15500f820bbbSmillert 		putchar('\n');
15510f820bbbSmillert 
15520f820bbbSmillert 		for (;;) {
1553c33fcabaSmillert 			s = getstring("Disk type",
1554803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1555803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
155696a888c6Smillert 			if (s == NULL)
155796a888c6Smillert 				continue;
15585b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15595b412421Smillert 				lp->d_type = DTYPE_ESDI;
15605b412421Smillert 				return;
15615b412421Smillert 			}
15620f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15630f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15640f820bbbSmillert 					lp->d_type = i;
15650f820bbbSmillert 					return;
15660f820bbbSmillert 				}
15670f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15680f820bbbSmillert 			fputs("Valid types are: ", stdout);
15690f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15700f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15710f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15720f820bbbSmillert 					fputs(", ", stdout);
15730f820bbbSmillert 			}
15740f820bbbSmillert 			putchar('\n');
15750f820bbbSmillert 		}
15760f820bbbSmillert 	}
15770f820bbbSmillert }
157896a888c6Smillert 
157996a888c6Smillert /*
158096a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
158196a888c6Smillert  * from the user.
158296a888c6Smillert  */
158396a888c6Smillert void
15849fdcb4d6Skrw set_bounds(struct disklabel *lp)
158596a888c6Smillert {
15861e0ad43cSotto 	u_int64_t ui, start_temp;
158796a888c6Smillert 
158896a888c6Smillert 	/* Starting sector */
158996a888c6Smillert 	do {
1590dea75673Skrw 		ui = getuint(lp, "Starting sector",
159196a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
15921e0ad43cSotto 		  starting_sector, DL_GETDSIZE(lp), 0, 0);
15931e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
159496a888c6Smillert 			fputs("Command aborted\n", stderr);
159596a888c6Smillert 			return;
159696a888c6Smillert 		}
15971e0ad43cSotto 	} while (ui >= DL_GETDSIZE(lp));
159896a888c6Smillert 	start_temp = ui;
159996a888c6Smillert 
16004793b14cSmillert 	/* Size */
160196a888c6Smillert 	do {
1602dea75673Skrw 		ui = getuint(lp, "Size ('*' for entire disk)",
1603f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1604f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
16051e0ad43cSotto 		  DL_GETDSIZE(lp) - start_temp, 0, 0);
16061e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
160796a888c6Smillert 			fputs("Command aborted\n", stderr);
160896a888c6Smillert 			return;
160996a888c6Smillert 		}
16101e0ad43cSotto 	} while (ui > DL_GETDSIZE(lp) - start_temp);
16114793b14cSmillert 	ending_sector = start_temp + ui;
161296a888c6Smillert 	starting_sector = start_temp;
161396a888c6Smillert }
161496a888c6Smillert 
161596a888c6Smillert /*
161696a888c6Smillert  * Return a list of the "chunks" of free space available
161796a888c6Smillert  */
161896a888c6Smillert struct diskchunk *
16198809fabbSderaadt free_chunks(struct disklabel *lp)
162096a888c6Smillert {
162196a888c6Smillert 	struct partition **spp;
162296a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
162399bd27d2Skrw 	u_int64_t start, stop;
162496a888c6Smillert 	int i, numchunks;
162596a888c6Smillert 
16260fbd3c97Skrw 	/* Sort the in-use partitions based on offset */
16270fbd3c97Skrw 	spp = sort_partitions(lp);
162896a888c6Smillert 
162996a888c6Smillert 	/* If there are no partitions, it's all free. */
16300fbd3c97Skrw 	if (spp[0] == NULL) {
16312d8451b0Smillert 		chunks[0].start = starting_sector;
163296a888c6Smillert 		chunks[0].stop = ending_sector;
163396a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
163496a888c6Smillert 		return(chunks);
163596a888c6Smillert 	}
163696a888c6Smillert 
163796a888c6Smillert 	/* Find chunks of free space */
163896a888c6Smillert 	numchunks = 0;
16390fbd3c97Skrw 	if (DL_GETPOFFSET(spp[0]) > starting_sector) {
16402d8451b0Smillert 		chunks[0].start = starting_sector;
16411e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
164296a888c6Smillert 		numchunks++;
164396a888c6Smillert 	}
16440fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
164599bd27d2Skrw 		start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1646aff3f969Sotto 		if (start < starting_sector)
1647aff3f969Sotto 			start = starting_sector;
1648aff3f969Sotto 		else if (start > ending_sector)
1649aff3f969Sotto 			start = ending_sector;
165099bd27d2Skrw 		if (spp[i + 1] != NULL)
165199bd27d2Skrw 			stop = DL_GETPOFFSET(spp[i+1]);
165299bd27d2Skrw 		else
165399bd27d2Skrw 			stop = ending_sector;
1654aff3f969Sotto 		if (stop < starting_sector)
1655aff3f969Sotto 			stop = starting_sector;
1656aff3f969Sotto 		else if (stop > ending_sector)
1657aff3f969Sotto 			stop = ending_sector;
165899bd27d2Skrw 		if (start < stop) {
165999bd27d2Skrw 			chunks[numchunks].start = start;
166099bd27d2Skrw 			chunks[numchunks].stop = stop;
166196a888c6Smillert 			numchunks++;
166296a888c6Smillert 		}
166396a888c6Smillert 	}
166496a888c6Smillert 
166596a888c6Smillert 	/* Terminate and return */
166696a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
166796a888c6Smillert 	return(chunks);
166896a888c6Smillert }
16694793b14cSmillert 
16704793b14cSmillert void
167187023ed9Skrw find_bounds(struct disklabel *lp)
16724793b14cSmillert {
16736534e983Sderaadt 	starting_sector = DL_GETBSTART(lp);
16746534e983Sderaadt 	ending_sector = DL_GETBEND(lp);
1675b2d4a455Smiod 
16766534e983Sderaadt 	if (ending_sector) {
167734ae4198Skrw 		if (verbose)
167834ae4198Skrw 			printf("Treating sectors %llu-%llu as the OpenBSD"
167934ae4198Skrw 			    " portion of the disk.\nYou can use the 'b'"
168034ae4198Skrw 			    " command to change this.\n\n", starting_sector,
168134ae4198Skrw 			    ending_sector);
1682b2d4a455Smiod 	} else {
1683b2d4a455Smiod #if (NUMBOOT == 1)
1684d3f02056Smillert 		/* Boot blocks take up the first cylinder */
1685d3f02056Smillert 		starting_sector = lp->d_secpercyl;
168634ae4198Skrw 		if (verbose)
168734ae4198Skrw 			printf("Reserving the first data cylinder for boot"
168834ae4198Skrw 			    " blocks.\nYou can use the 'b' command to change"
168934ae4198Skrw 			    " this.\n\n");
16904793b14cSmillert #endif
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
17138809fabbSderaadt editor_help(char *arg)
1714617e6e4aSmillert {
1715617e6e4aSmillert 
1716617e6e4aSmillert 	/* XXX - put these strings in a table instead? */
1717617e6e4aSmillert 	switch (*arg) {
1718617e6e4aSmillert 	case 'p':
1719617e6e4aSmillert 		puts(
1720aff3f969Sotto "The 'p' command prints the current partitions.  By default, it prints size\n"
1721aff3f969Sotto "and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1722aff3f969Sotto "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1723aff3f969Sotto "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1724eb176802Sjsg 		break;
1725aff3f969Sotto 	case 'l':
1726aff3f969Sotto 	puts(
1727aff3f969Sotto "The 'l' command prints the header of the disk label.  By default, it prints\n"
1728617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1729617e6e4aSmillert "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1730617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1731617e6e4aSmillert 		break;
1732617e6e4aSmillert 	case 'M':
1733617e6e4aSmillert 		puts(
17349afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n"
1735508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n"
1736508086e9Smillert "not set.  It is especially useful during install when the normal system\n"
1737508086e9Smillert "manual is not available.\n");
1738617e6e4aSmillert 		break;
1739617e6e4aSmillert 	case 'e':
1740617e6e4aSmillert 		puts(
1741617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters.  These include\n"
1742617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n"
1743617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n"
1744617e6e4aSmillert "type, and a descriptive label string.  You should not change these unless\n"
1745617e6e4aSmillert "you know what you are doing\n");
1746617e6e4aSmillert 		break;
1747617e6e4aSmillert 	case 'a':
1748617e6e4aSmillert 		puts(
1749617e6e4aSmillert "The 'a' command adds new partitions to the disk.  It takes as an optional\n"
1750617e6e4aSmillert "argument the partition letter to add.  If you do not specify a partition\n"
1751617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n"
1752617e6e4aSmillert "default answer\n");
1753617e6e4aSmillert 		break;
17546aaa4aabSotto 	case 'A':
17556aaa4aabSotto 		puts(
17566aaa4aabSotto "The 'A' command clears the existing partitions and creates a new label\n"
17576aaa4aabSotto "based on the size of the disk\n");
17586aaa4aabSotto 		break;
1759617e6e4aSmillert 	case 'b':
1760617e6e4aSmillert 		puts(
1761617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n"
1762617e6e4aSmillert "the disk.  This is only useful on disks with an fdisk partition.  By default,\n"
1763617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n"
1764617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition.  You should only change\n"
1765617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n"
1766617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be.  You\n"
1767617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n"
1768617e6e4aSmillert "(minus the starting sector).  Use this option with care; if you extend the\n"
1769617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n"
1770617e6e4aSmillert "corrupt the other operating system's data.\n");
1771617e6e4aSmillert 		break;
1772617e6e4aSmillert 	case 'c':
1773617e6e4aSmillert 		puts(
1774617e6e4aSmillert "The 'c' command is used to change the size of an existing partition.  It\n"
1775617e6e4aSmillert "takes as an optional argument the partition letter to change.  If you do not\n"
1776617e6e4aSmillert "specify a partition letter, you will be prompted for one.  You may add a '+'\n"
1777617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n"
1778617e6e4aSmillert "instead of entering an absolute value.  You may also use a suffix to indicate\n"
1779617e6e4aSmillert "the units the values is in terms of.  Possible suffixes are 'b' for bytes,\n"
1780617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n"
1781617e6e4aSmillert "no suffix for sectors (usually 512 bytes).  You may also enter '*' to change\n"
1782617e6e4aSmillert "the size to be the total number of free sectors remaining.\n");
1783617e6e4aSmillert 		break;
17849afbe9eeSmillert 	case 'D':
17859afbe9eeSmillert 		puts(
17869afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n"
17879afbe9eeSmillert "by the disk itself.  This similates the case where there is no disk label.\n");
17889afbe9eeSmillert 		break;
1789617e6e4aSmillert 	case 'd':
1790617e6e4aSmillert 		puts(
1791617e6e4aSmillert "The 'd' command is used to delete an existing partition.  It takes as an\n"
1792617e6e4aSmillert "optional argument the partition letter to change.  If you do not specify a\n"
1793617e6e4aSmillert "partition letter, you will be prompted for one.  You may not delete the ``c''\n"
1794617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n"
1795617e6e4aSmillert "it does not take up any space).\n");
1796617e6e4aSmillert 		break;
1797c33fcabaSmillert 	case 'g':
1798c33fcabaSmillert 		puts(
179987023ed9Skrw "The 'g' command is used select which disk geometry to use, the disk or a\n"
180087023ed9Skrw "user geometry.  It takes as an optional argument ``d'' or ``u''.  If \n"
1801c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n");
1802c33fcabaSmillert 		break;
1803617e6e4aSmillert 	case 'm':
1804617e6e4aSmillert 		puts(
180587023ed9Skrw "The 'm' command is used to modify an existing partition.  It takes as an\n"
180687023ed9Skrw "optional argument the partition letter to change.  If you do not specify a\n"
1807617e6e4aSmillert "partition letter, you will be prompted for one.  This option allows the user\n"
1808617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n"
1809617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n"
1810617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n");
1811617e6e4aSmillert 		break;
1812bd6726faSmillert 	case 'n':
1813bd6726faSmillert 		puts(
1814fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n"
1815bd6726faSmillert "It takes as an optional argument the partition letter to name.  If you do\n"
1816bd6726faSmillert "not specify a partition letter, you will be prompted for one.  This option\n"
1817ac7ae62cSderaadt "is only valid if disklabel was invoked with the -f flag.\n");
1818bd6726faSmillert 		break;
18196aaa4aabSotto 	case 'R':
18206aaa4aabSotto 		puts(
18216aaa4aabSotto "Resize a a partition, compacting unused space between partitions\n"
18226aaa4aabSotto "with a higher offset. The last partition will be shrunk if needed.\n"
18236aaa4aabSotto "Works only for auto allocated labels with no spoofed partitions\n");
18246aaa4aabSotto 		break;
1825617e6e4aSmillert 	case 'r':
1826617e6e4aSmillert 		puts(
182725f9c360Skrw "The 'r' command is used to recalculate and display details about\n"
182825f9c360Skrw "the available free space.\n");
1829617e6e4aSmillert 		break;
1830617e6e4aSmillert 	case 'u':
1831617e6e4aSmillert 		puts(
1832617e6e4aSmillert "The 'u' command will undo (or redo) the last change.  Entering 'u' once will\n"
1833617e6e4aSmillert "undo your last change.  Entering it again will restore the change.\n");
1834617e6e4aSmillert 		break;
1835617e6e4aSmillert 	case 's':
1836617e6e4aSmillert 		puts(
1837617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n"
1838617e6e4aSmillert "(suitable for loading via disklabel's [-R] option).  It takes as an optional\n"
1839617e6e4aSmillert "argument the filename to save the label to.  If you do not specify a filename,\n"
1840617e6e4aSmillert "you will be prompted for one.\n");
1841617e6e4aSmillert 		break;
1842617e6e4aSmillert 	case 'w':
1843617e6e4aSmillert 		puts(
1844617e6e4aSmillert "The 'w' command will write the current label to disk.  This option will\n"
1845617e6e4aSmillert "commit any changes to the on-disk label.\n");
1846617e6e4aSmillert 		break;
1847617e6e4aSmillert 	case 'q':
1848617e6e4aSmillert 		puts(
1849617e6e4aSmillert "The 'q' command quits the label editor.  If any changes have been made you\n"
1850617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n");
1851617e6e4aSmillert 		break;
18529afbe9eeSmillert 	case 'X':
18539afbe9eeSmillert 		puts(
18549afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'.  By default,\n"
18559afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n"
18569afbe9eeSmillert "size on ffs partitions).\n");
18579afbe9eeSmillert 		break;
1858617e6e4aSmillert 	case 'x':
1859617e6e4aSmillert 		puts(
1860617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n"
1861617e6e4aSmillert "on-disk label.\n");
1862617e6e4aSmillert 		break;
18639afbe9eeSmillert 	case 'z':
18649afbe9eeSmillert 		puts(
18659afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n"
18669afbe9eeSmillert "partition.  The drive parameters are not changed.\n");
18679afbe9eeSmillert 		break;
1868617e6e4aSmillert 	default:
1869617e6e4aSmillert 		puts("Available commands:");
1870617e6e4aSmillert 		puts(
187149159a67Skrw "  ? [cmd]  - show help                  n [part] - set mount point\n"
187249159a67Skrw "  A        - auto partition all space   p [unit] - print partitions\n"
187349159a67Skrw "  a [part] - add partition              q        - quit & save changes\n"
18746aaa4aabSotto "  b        - set OpenBSD boundaries     R [part] - resize a partition\n"
187549159a67Skrw "  c [part] - change partition size      r        - display free space\n"
18766aaa4aabSotto "  D        - reset label to default     s [path] - save label to file\n"
18776aaa4aabSotto "  d [part] - delete partition           U        - undo all changes\n"
18786aaa4aabSotto "  e        - edit drive parameters      u        - undo last change\n"
18796aaa4aabSotto "  g [d|u]  - [d]isk or [u]ser geometry  w        - write label to disk\n"
18806aaa4aabSotto "  l [unit] - print disk label header    X        - toggle expert mode\n"
18816aaa4aabSotto "  M        - disklabel(8) man page      x        - exit & lose changes\n"
18826aaa4aabSotto "  m [part] - modify partition           z        - delete all partitions\n"
1883c4884206Skrw "\n"
1884c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1885c4884206Skrw "\t'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes)\n"
1886c4884206Skrw "\t'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1887c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
1888617e6e4aSmillert 		break;
1889617e6e4aSmillert 	}
1890617e6e4aSmillert }
1891bd6726faSmillert 
18924f3bbbf0Skrw void
18938809fabbSderaadt mpcopy(char **to, char **from)
1894bd6726faSmillert {
1895bd6726faSmillert 	int i;
18960612d09dSderaadt 	char *top;
1897bd6726faSmillert 
1898bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1899bd6726faSmillert 		if (from[i] != NULL) {
1900dcab0d16Sderaadt 			int len = strlen(from[i]) + 1;
1901dcab0d16Sderaadt 
19020612d09dSderaadt 			top = realloc(to[i], len);
19030612d09dSderaadt 			if (top == NULL)
1904bd6726faSmillert 				errx(4, "out of memory");
19050612d09dSderaadt 			to[i] = top;
1906dcab0d16Sderaadt 			(void)strlcpy(to[i], from[i], len);
1907bd6726faSmillert 		} else if (to[i] != NULL) {
1908bd6726faSmillert 			free(to[i]);
1909bd6726faSmillert 			to[i] = NULL;
1910bd6726faSmillert 		}
1911bd6726faSmillert 	}
1912bd6726faSmillert }
1913bd6726faSmillert 
1914bd6726faSmillert int
19158809fabbSderaadt mpequal(char **mp1, char **mp2)
1916bd6726faSmillert {
1917bd6726faSmillert 	int i;
1918bd6726faSmillert 
1919bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1920bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1921bd6726faSmillert 			continue;
1922bd6726faSmillert 
1923bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1924bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1925bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1926bd6726faSmillert 			return(0);
1927bd6726faSmillert 	}
1928bd6726faSmillert 	return(1);
1929bd6726faSmillert }
1930bd6726faSmillert 
193193160b9bSkrw void
193234ae4198Skrw mpsave(struct disklabel *lp)
1933bd6726faSmillert {
1934d8b446ceSderaadt 	int i, j;
1935bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
19363f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1937bd6726faSmillert 	FILE *fp;
1938bd6726faSmillert 
193993160b9bSkrw 	if (!fstabfile)
194093160b9bSkrw 		return;
194193160b9bSkrw 
19423f843443Smillert 	memset(&mi, 0, sizeof(mi));
19433f843443Smillert 
1944d8b446ceSderaadt 	for (i = 0; i < MAXPARTITIONS; i++) {
194534ae4198Skrw 		if (mountpoints[i] != NULL) {
194634ae4198Skrw 			mi[i].mountpoint = mountpoints[i];
19473f843443Smillert 			mi[i].partno = i;
1948bd6726faSmillert 		}
1949bd6726faSmillert 	}
1950bd6726faSmillert 
195134ae4198Skrw 	/* Convert specname to bdev */
195234ae4198Skrw 	if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
195334ae4198Skrw 	    specname[sizeof(_PATH_DEV) - 1] == 'r') {
1954bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
195534ae4198Skrw 		    &specname[sizeof(_PATH_DEV)]);
1956bd6726faSmillert 	} else {
195734ae4198Skrw 		if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
195893160b9bSkrw 			return;
1959bd6726faSmillert 		*p = '\0';
196034ae4198Skrw 		snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1961bd6726faSmillert 		*p = 'r';
1962bd6726faSmillert 	}
1963bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1964bd6726faSmillert 
19653f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
19663f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
19673f843443Smillert 
196893160b9bSkrw 	if (fp = fopen(fstabfile, "w")) {
196993160b9bSkrw 		for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint; i++) {
19705fea0b85Smillert 			j =  mi[i].partno;
19715fea0b85Smillert 			fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j,
19723f843443Smillert 			    mi[i].mountpoint,
19735fea0b85Smillert 			    fstypesnames[lp->d_partitions[j].p_fstype],
19745fea0b85Smillert 			    j == 0 ? 1 : 2);
1975bd6726faSmillert 		}
1976bd6726faSmillert 		fclose(fp);
197793160b9bSkrw 	}
1978bd6726faSmillert }
197924a2c1a4Smillert 
198024a2c1a4Smillert int
1981604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
198224a2c1a4Smillert {
1983604d3bdeSkrw 	struct diskchunk *chunks;
198424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
198515c15d8aSkrw 	u_int64_t ui, maxsize;
1986604d3bdeSkrw 	int i, fstype;
198724a2c1a4Smillert 
1988dea75673Skrw 	ui = getuint(lp, "offset",
19891e0ad43cSotto 	   "Starting sector for this partition.",
19901e0ad43cSotto 	   DL_GETPOFFSET(pp),
19911e0ad43cSotto 	   DL_GETPOFFSET(pp), 0, DO_CONVERSIONS |
199224a2c1a4Smillert 	   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
1993e9ff19beSkrw 
1994e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
199524a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1996e9ff19beSkrw 	else if (ui == ULLONG_MAX)
199724a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
199840e98e9fSkrw 	else if (ui < starting_sector || ui >= ending_sector)
1999e9ff19beSkrw 		fprintf(stderr, "The offset must be >= %llu and < %llu, "
2000e9ff19beSkrw 		    "the limits of the OpenBSD portion\n"
2001e9ff19beSkrw 		    "of the disk. The 'b' command can change these limits.\n",
200240e98e9fSkrw 		    starting_sector, ending_sector);
2003fc1a4cc6Sderaadt #ifdef SUN_AAT0
200449bf537cSderaadt 	else if (partno == 0 && ui != 0)
200549bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
200640f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
200749bf537cSderaadt #endif
200815c15d8aSkrw 	else {
2009604d3bdeSkrw 		fstype = pp->p_fstype;
2010604d3bdeSkrw 		pp->p_fstype = FS_UNUSED;
2011604d3bdeSkrw 		chunks = free_chunks(lp);
2012604d3bdeSkrw 		pp->p_fstype = fstype;
2013e9ff19beSkrw 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
2014e9ff19beSkrw 			if (ui < chunks[i].start || ui >= chunks[i].stop)
201515c15d8aSkrw 				continue;
20161e0ad43cSotto 			DL_SETPOFFSET(pp, ui);
201715c15d8aSkrw 			maxsize = chunks[i].stop - DL_GETPOFFSET(pp);
201815c15d8aSkrw 			if (DL_GETPSIZE(pp) > maxsize)
201915c15d8aSkrw 				DL_SETPSIZE(pp, maxsize);
202024a2c1a4Smillert 			return (0);
202124a2c1a4Smillert 		}
202215c15d8aSkrw 		fputs("The offset must be in a free area.\n", stderr);
202315c15d8aSkrw 	}
2024e9ff19beSkrw 
2025e9ff19beSkrw 	/* Partition offset was not set. */
2026e9ff19beSkrw 	return (1);
202715c15d8aSkrw }
202824a2c1a4Smillert 
202924a2c1a4Smillert int
20309fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
203124a2c1a4Smillert {
203224a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
203314192793Skrw 	u_int64_t maxsize, ui;
203414192793Skrw 
203514192793Skrw 	maxsize = max_partition_size(lp, partno);
203624a2c1a4Smillert 
2037dea75673Skrw 	ui = getuint(lp, "size", "Size of the partition. "
20387da73705Skrw 	    "You may also say +/- amount for a relative change.",
203914192793Skrw 	    DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp),
2040525051f1Sotto 	    DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS ||
2041525051f1Sotto 	    pp->p_fstype == FS_SWAP) ?  DO_ROUNDING : 0));
2042e9ff19beSkrw 
2043e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
204424a2c1a4Smillert 		fputs("Command aborted\n", stderr);
2045e9ff19beSkrw 	else if (ui == ULLONG_MAX)
204624a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
204728e3704eSkrw 	else if (ui == 0)
204828e3704eSkrw 		fputs("The size must be > 0\n", stderr);
204940e98e9fSkrw 	else if (ui + DL_GETPOFFSET(pp) > ending_sector)
205040e98e9fSkrw 		fprintf(stderr, "The size can't be more than "
205140e98e9fSkrw 		    "%llu sectors, or the partition would\n"
205240e98e9fSkrw 		    "extend beyond the last sector (%llu) of the "
205340e98e9fSkrw 		    "OpenBSD portion of\nthe disk. "
205440e98e9fSkrw 		    "The 'b' command can change this limit.\n",
205540e98e9fSkrw 		    ending_sector - DL_GETPOFFSET(pp), ending_sector);
205614192793Skrw 	else if (ui > maxsize)
205714192793Skrw 		fprintf(stderr,"Sorry, there are only %llu sectors left\n",
205814192793Skrw 		    maxsize);
205959ccf790Skrw 	else {
206059ccf790Skrw 		DL_SETPSIZE(pp, ui);
206124a2c1a4Smillert 		return (0);
206224a2c1a4Smillert 	}
2063e9ff19beSkrw 
2064e9ff19beSkrw 	/* Partition size was not set. */
2065e9ff19beSkrw 	return (1);
2066e9ff19beSkrw }
206724a2c1a4Smillert 
206824a2c1a4Smillert int
20698809fabbSderaadt get_fsize(struct disklabel *lp, int partno)
207024a2c1a4Smillert {
20711e0ad43cSotto 	u_int64_t ui, fsize, frag;
207224a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
207324a2c1a4Smillert 
2074a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
2075a4c87e64Skrw 		return (0);
2076a4c87e64Skrw 
2077ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
2078ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
2079ddfcbf38Sotto 	if (fsize == 0)
2080ddfcbf38Sotto 		frag = 8;
2081ddfcbf38Sotto 
208224a2c1a4Smillert 	for (;;) {
2083dea75673Skrw 		ui = getuint(lp, "fragment size",
20843c92d7f2Stedu 		    "Size of fs block fragments.  Usually 2048 or 512.",
2085ddfcbf38Sotto 		    fsize, fsize, 0, 0);
20861e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
208724a2c1a4Smillert 			fputs("Command aborted\n", stderr);
208824a2c1a4Smillert 			return(1);
20891e0ad43cSotto 		} else if (ui == ULLONG_MAX)
209024a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
209124a2c1a4Smillert 		else
209224a2c1a4Smillert 			break;
209324a2c1a4Smillert 	}
209424a2c1a4Smillert 	if (ui == 0)
209524a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
2096ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag);
209724a2c1a4Smillert 	return(0);
209824a2c1a4Smillert }
209924a2c1a4Smillert 
210024a2c1a4Smillert int
21018809fabbSderaadt get_bsize(struct disklabel *lp, int partno)
210224a2c1a4Smillert {
21031e0ad43cSotto 	u_int64_t ui, bsize, frag, fsize;
210424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
210524a2c1a4Smillert 
2106a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
2107a4c87e64Skrw 		return (0);
2108a4c87e64Skrw 
210924a2c1a4Smillert 	/* Avoid dividing by zero... */
2110ddfcbf38Sotto 	if (pp->p_fragblock == 0)
211124a2c1a4Smillert 		return(1);
2112ddfcbf38Sotto 
2113ddfcbf38Sotto 	bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock);
2114ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
2115ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
211624a2c1a4Smillert 
211724a2c1a4Smillert 	for (;;) {
2118dea75673Skrw 		ui = getuint(lp, "block size",
21193c92d7f2Stedu 		    "Size of filesystem blocks.  Usually 16384 or 4096.",
2120ddfcbf38Sotto 		    fsize * frag, fsize * frag,
212124a2c1a4Smillert 		    0, 0);
212224a2c1a4Smillert 
212324a2c1a4Smillert 		/* sanity checks */
21241e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
212524a2c1a4Smillert 			fputs("Command aborted\n", stderr);
212624a2c1a4Smillert 			return(1);
21271e0ad43cSotto 		} else if (ui == ULLONG_MAX)
212824a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
212924a2c1a4Smillert 		else if (ui < getpagesize())
213024a2c1a4Smillert 			fprintf(stderr,
213124a2c1a4Smillert 			    "Error: block size must be at least as big "
213224a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
2133ddfcbf38Sotto 		else if (ui % fsize != 0)
213424a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
213524a2c1a4Smillert 			    "fragment size.\n", stderr);
2136ddfcbf38Sotto 		else if (ui / fsize < 1)
213724a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
213824a2c1a4Smillert 			    "fragment size.\n", stderr);
213924a2c1a4Smillert 		else
214024a2c1a4Smillert 			break;
214124a2c1a4Smillert 	}
2142ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag);
214324a2c1a4Smillert 	return(0);
214424a2c1a4Smillert }
214524a2c1a4Smillert 
214624a2c1a4Smillert int
21478809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
214824a2c1a4Smillert {
214924a2c1a4Smillert 	char *p;
21501e0ad43cSotto 	u_int64_t ui;
215124a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
215224a2c1a4Smillert 
215324a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
2154c33fcabaSmillert 		p = getstring("FS type",
215524a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
215624a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
215724a2c1a4Smillert 		if (p == NULL) {
215824a2c1a4Smillert 			fputs("Command aborted\n", stderr);
215924a2c1a4Smillert 			return(1);
216024a2c1a4Smillert 		}
216124a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
216224a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
216324a2c1a4Smillert 				pp->p_fstype = ui;
216424a2c1a4Smillert 				break;
216524a2c1a4Smillert 			}
216624a2c1a4Smillert 		}
216724a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
216824a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
216924a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
217024a2c1a4Smillert 		}
217124a2c1a4Smillert 	} else {
217224a2c1a4Smillert 		for (;;) {
2173dea75673Skrw 			ui = getuint(lp, "FS type (decimal)",
217424a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
217524a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
21761e0ad43cSotto 			if (ui == ULLONG_MAX - 1) {
217724a2c1a4Smillert 				fputs("Command aborted\n", stderr);
217824a2c1a4Smillert 				return(1);
21791e0ad43cSotto 			} if (ui == ULLONG_MAX)
218024a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
218124a2c1a4Smillert 			else
218224a2c1a4Smillert 				break;
218324a2c1a4Smillert 		}
218424a2c1a4Smillert 		pp->p_fstype = ui;
218524a2c1a4Smillert 	}
218624a2c1a4Smillert 	return(0);
218724a2c1a4Smillert }
218824a2c1a4Smillert 
218924a2c1a4Smillert int
219034ae4198Skrw get_mp(struct disklabel *lp, int partno)
219124a2c1a4Smillert {
219224a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
2193ec9fde5fSkrw 	char *p;
2194ec9fde5fSkrw 	int i;
219524a2c1a4Smillert 
219634ae4198Skrw 	if (fstabfile && pp->p_fstype != FS_UNUSED &&
219724a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
219824a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
2199ddaff619Smillert 		for (;;) {
2200c33fcabaSmillert 			p = getstring("mount point",
220124a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
220234ae4198Skrw 			    mountpoints[partno] ? mountpoints[partno] : "none");
220324a2c1a4Smillert 			if (p == NULL) {
220424a2c1a4Smillert 				fputs("Command aborted\n", stderr);
220524a2c1a4Smillert 				return(1);
220624a2c1a4Smillert 			}
2207ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
220834ae4198Skrw 				free(mountpoints[partno]);
220934ae4198Skrw 				mountpoints[partno] = NULL;
2210ddaff619Smillert 				break;
2211ddaff619Smillert 			}
2212ec9fde5fSkrw 			for (i = 0; i < MAXPARTITIONS; i++)
221393160b9bSkrw 				if (mountpoints[i] != NULL && i != partno &&
2214ec9fde5fSkrw 				    strcmp(p, mountpoints[i]) == 0)
2215ec9fde5fSkrw 					break;
2216ec9fde5fSkrw 			if (i < MAXPARTITIONS) {
221793160b9bSkrw 				fprintf(stderr, "'%c' already being mounted at "
221893160b9bSkrw 				    "'%s'\n", 'a'+i, p);
2219ec9fde5fSkrw 				break;
2220ec9fde5fSkrw 			}
2221ddaff619Smillert 			if (*p == '/') {
2222ddaff619Smillert 				/* XXX - might as well realloc */
222334ae4198Skrw 				free(mountpoints[partno]);
222434ae4198Skrw 				if ((mountpoints[partno] = strdup(p)) == NULL)
222524a2c1a4Smillert 					errx(4, "out of memory");
2226ddaff619Smillert 				break;
2227ddaff619Smillert 			}
2228ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
222924a2c1a4Smillert 		}
223024a2c1a4Smillert 	}
223124a2c1a4Smillert 	return(0);
223224a2c1a4Smillert }
22333f843443Smillert 
22343f843443Smillert int
22358809fabbSderaadt micmp(const void *a1, const void *a2)
22363f843443Smillert {
22373f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
22383f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
22393f843443Smillert 
22403f843443Smillert 	/* We want all the NULLs at the end... */
22413f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
22423f843443Smillert 		return(0);
22433f843443Smillert 	else if (mi1->mountpoint == NULL)
22443f843443Smillert 		return(1);
22453f843443Smillert 	else if (mi2->mountpoint == NULL)
22463f843443Smillert 		return(-1);
22473f843443Smillert 	else
22483f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
22493f843443Smillert }
2250c33fcabaSmillert 
2251c33fcabaSmillert void
225287023ed9Skrw get_geometry(int f, struct disklabel **dgpp)
2253c33fcabaSmillert {
2254c33fcabaSmillert 	struct stat st;
2255c33fcabaSmillert 	struct disklabel *disk_geop;
225687023ed9Skrw 
2257c33fcabaSmillert 	if (fstat(f, &st) == -1)
2258c33fcabaSmillert 		err(4, "Can't stat device");
2259c33fcabaSmillert 
2260c33fcabaSmillert 	/* Get disk geometry */
2261c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2262c33fcabaSmillert 		errx(4, "out of memory");
2263c33fcabaSmillert 	if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 &&
2264c33fcabaSmillert 	    ioctl(f, DIOCGDINFO, disk_geop) < 0)
2265c33fcabaSmillert 		err(4, "ioctl DIOCGDINFO");
2266c33fcabaSmillert 	*dgpp = disk_geop;
2267c33fcabaSmillert }
2268c33fcabaSmillert 
2269c33fcabaSmillert void
22708809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp,
227187023ed9Skrw     struct disklabel *ugp, char *p)
2272c33fcabaSmillert {
2273c33fcabaSmillert 	if (p == NULL) {
22749a36aa41Ssthen 		p = getstring("[d]isk or [u]ser geometry",
2275c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
22769a36aa41Ssthen 		    "itself thinks it is, or 'u' to use the geometry that "
22779a36aa41Ssthen 		    "was found in the label.",
2278c33fcabaSmillert 		    "d");
2279c33fcabaSmillert 	}
2280c33fcabaSmillert 	if (p == NULL) {
2281c33fcabaSmillert 		fputs("Command aborted\n", stderr);
2282c33fcabaSmillert 		return;
2283c33fcabaSmillert 	}
2284c33fcabaSmillert 	switch (*p) {
2285c33fcabaSmillert 	case 'd':
2286c33fcabaSmillert 	case 'D':
2287c33fcabaSmillert 		if (dgp == NULL)
2288c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2289c33fcabaSmillert 		else {
2290c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
2291c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
2292c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
2293c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
2294c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
229534af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(dgp));
2296c33fcabaSmillert 		}
2297c33fcabaSmillert 		break;
2298c33fcabaSmillert 	case 'u':
2299c33fcabaSmillert 	case 'U':
2300c33fcabaSmillert 		if (ugp == NULL)
2301c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2302c33fcabaSmillert 		else {
2303c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2304c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2305c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2306c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2307c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
230834af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(ugp));
2309c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2310c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2311c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2312c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2313c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
231434af67a3Sotto 			    DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp))
2315c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2316c33fcabaSmillert 				    "geometry.\n", stderr);
2317c33fcabaSmillert 		}
2318c33fcabaSmillert 		break;
2319c33fcabaSmillert 	default:
23209a36aa41Ssthen 		fputs("You must enter either 'd' or 'u'.\n", stderr);
2321c33fcabaSmillert 		break;
2322c33fcabaSmillert 	}
2323c33fcabaSmillert }
23249afbe9eeSmillert 
23259afbe9eeSmillert void
23269fdcb4d6Skrw zero_partitions(struct disklabel *lp)
23279afbe9eeSmillert {
23289afbe9eeSmillert 	int i;
23299afbe9eeSmillert 
2330b4ed6301Skrw 	for (i = 0; i < MAXPARTITIONS; i++) {
23319afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
2332b4ed6301Skrw 		free(mountpoints[i]);
2333b4ed6301Skrw 		mountpoints[i] = NULL;
2334b4ed6301Skrw 	}
2335b4ed6301Skrw 
233634af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
23379afbe9eeSmillert }
233814192793Skrw 
233914192793Skrw u_int64_t
234014192793Skrw max_partition_size(struct disklabel *lp, int partno)
234114192793Skrw {
234214192793Skrw 	struct partition *pp = &lp->d_partitions[partno];
234314192793Skrw 	struct diskchunk *chunks;
2344*44ffe03bSotto 	u_int64_t maxsize = 0, offset;
234514192793Skrw 	int fstype, i;
234614192793Skrw 
234714192793Skrw 	fstype = pp->p_fstype;
234814192793Skrw 	pp->p_fstype = FS_UNUSED;
234914192793Skrw 	chunks = free_chunks(lp);
235014192793Skrw 	pp->p_fstype = fstype;
235114192793Skrw 
235214192793Skrw 	offset = DL_GETPOFFSET(pp);
235314192793Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
235414192793Skrw 		if (offset < chunks[i].start || offset >= chunks[i].stop)
235514192793Skrw 			continue;
235614192793Skrw 		maxsize = chunks[i].stop - offset;
235714192793Skrw 		break;
235814192793Skrw 	}
235914192793Skrw 	return (maxsize);
236014192793Skrw }
2361aff3f969Sotto 
2362aff3f969Sotto void
2363aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp)
2364aff3f969Sotto {
2365aff3f969Sotto 	double d = scale(sz, unit, lp);
2366aff3f969Sotto 	if (d < 0)
2367aff3f969Sotto 		printf("%llu", sz);
2368aff3f969Sotto 	else
2369aff3f969Sotto 		printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
2370aff3f969Sotto }
2371aff3f969Sotto 
2372aff3f969Sotto void
237334ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr)
2374aff3f969Sotto {
2375aff3f969Sotto 	int i;
2376aff3f969Sotto 
2377352d199bSkrw 	unit = canonical_unit(lp, unit);
2378aff3f969Sotto 
2379aff3f969Sotto 	printf("OpenBSD area: ");
238059882f1dSkrw 	psize(starting_sector, 0, lp);
2381aff3f969Sotto 	printf("-");
238259882f1dSkrw 	psize(ending_sector, 0, lp);
2383aff3f969Sotto 	printf("; size: ");
2384aff3f969Sotto 	psize(ending_sector - starting_sector, unit, lp);
2385aff3f969Sotto 	printf("; free: ");
2386aff3f969Sotto 	psize(fr, unit, lp);
2387aff3f969Sotto 
2388aff3f969Sotto 	printf("\n#    %16.16s %16.16s  fstype [fsize bsize  cpg]\n",
2389aff3f969Sotto 	    "size", "offset");
2390aff3f969Sotto 	for (i = 0; i < lp->d_npartitions; i++)
239134ae4198Skrw 		display_partition(stdout, lp, i, unit);
2392aff3f969Sotto }
2393aff3f969Sotto 
2394