xref: /openbsd/sbin/disklabel/editor.c (revision d7878011)
1*d7878011Sderaadt /*	$OpenBSD: editor.c,v 1.259 2011/10/06 21:16:01 deraadt Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
42d8451b0Smillert  * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert  */
186fe57b42Smillert 
196fe57b42Smillert #include <sys/types.h>
206fe57b42Smillert #include <sys/param.h>
21c33fcabaSmillert #include <sys/stat.h>
22c33fcabaSmillert #include <sys/ioctl.h>
2391f4f7d8Sdlg #include <sys/dkio.h>
248dde8bb6Sotto #include <sys/sysctl.h>
256fe57b42Smillert #define	DKTYPENAMES
266fe57b42Smillert #include <sys/disklabel.h>
276fe57b42Smillert 
286fe57b42Smillert #include <ufs/ffs/fs.h>
296fe57b42Smillert 
306fe57b42Smillert #include <ctype.h>
316fe57b42Smillert #include <err.h>
326fe57b42Smillert #include <errno.h>
336fe57b42Smillert #include <string.h>
34803ff7d5Smillert #include <libgen.h>
356fe57b42Smillert #include <stdio.h>
366fe57b42Smillert #include <stdlib.h>
376fe57b42Smillert #include <unistd.h>
386fe57b42Smillert 
39f21a098bSotto #include "extern.h"
404793b14cSmillert #include "pathnames.h"
414793b14cSmillert 
426fe57b42Smillert /* flags for getuint() */
436fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
446fe57b42Smillert #define	DO_ROUNDING	0x00000002
456fe57b42Smillert 
46f98aebd4Smillert #ifndef NUMBOOT
47f98aebd4Smillert #define NUMBOOT 0
48f98aebd4Smillert #endif
49f98aebd4Smillert 
5096a888c6Smillert /* structure to describe a portion of a disk */
5196a888c6Smillert struct diskchunk {
521e0ad43cSotto 	u_int64_t start;
531e0ad43cSotto 	u_int64_t stop;
5496a888c6Smillert };
5596a888c6Smillert 
563f843443Smillert /* used when sorting mountpoints in mpsave() */
573f843443Smillert struct mountinfo {
583f843443Smillert 	char *mountpoint;
593f843443Smillert 	int partno;
603f843443Smillert };
613f843443Smillert 
62557f712bSkrw /* used when allocating all space according to recommendations */
63557f712bSkrw 
64557f712bSkrw struct space_allocation {
655f3e1104Skrw 	daddr64_t	minsz;	/* starts as blocks, xlated to sectors. */
665f3e1104Skrw 	daddr64_t	maxsz;	/* starts as blocks, xlated to sectors. */
67557f712bSkrw 	int		rate;	/* % of extra space to use */
68557f712bSkrw 	char	       *mp;
69557f712bSkrw };
70557f712bSkrw 
718dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
728dde8bb6Sotto const struct space_allocation alloc_big[] = {
7392adb55fSderaadt 	{   MEG(80),         GIG(1),   5, "/"		},
748dde8bb6Sotto 	{   MEG(80),       MEG(256),   5, "swap"	},
754ab111d2Sderaadt 	{  MEG(120),         GIG(4),   8, "/tmp"	},
7692adb55fSderaadt 	{   MEG(80),         GIG(4),  13, "/var"	},
7721a0d117Sderaadt 	{  MEG(900),         GIG(2),   5, "/usr"	},
7892adb55fSderaadt 	{  MEG(512),         GIG(1),   3, "/usr/X11R6"	},
796e1f4775Sotto 	{    GIG(2),        GIG(10),  10, "/usr/local"	},
802cb42124Sotto 	{    GIG(1),         GIG(2),   2, "/usr/src"	},
81001bee15Sotto #ifdef STATICLINKING
82001bee15Sotto 	{ MEG(2600),         GIG(3),   4, "/usr/obj"	},
83001bee15Sotto #else
842cb42124Sotto 	{ MEG(1300),         GIG(2),   4, "/usr/obj"	},
85001bee15Sotto #endif
866e1f4775Sotto 	{    GIG(1),       GIG(300),  45, "/home"	}
874ab111d2Sderaadt 	/* Anything beyond this leave for the user to decide */
888dde8bb6Sotto };
898dde8bb6Sotto 
908dde8bb6Sotto const struct space_allocation alloc_medium[] = {
91905e8239Sderaadt 	{  MEG(800),         GIG(2),   5, "/"		},
928dde8bb6Sotto 	{   MEG(80),       MEG(256),  10, "swap"	},
93905e8239Sderaadt 	{  MEG(900),         GIG(3),  78, "/usr"	},
94905e8239Sderaadt 	{  MEG(256),         GIG(2),   7, "/home"	}
958dde8bb6Sotto };
968dde8bb6Sotto 
978dde8bb6Sotto const struct space_allocation alloc_small[] = {
9892adb55fSderaadt 	{  MEG(700),         GIG(4),  95, "/"		},
998dde8bb6Sotto 	{    MEG(1),       MEG(256),   5, "swap"	}
1008dde8bb6Sotto };
1018dde8bb6Sotto 
1028dde8bb6Sotto const struct space_allocation alloc_stupid[] = {
1038dde8bb6Sotto 	{    MEG(1),      MEG(2048), 100, "/"		}
1048dde8bb6Sotto };
1058dde8bb6Sotto 
106b2813ff1Sderaadt #ifndef nitems
107b2813ff1Sderaadt #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
108b2813ff1Sderaadt #endif
109b2813ff1Sderaadt 
1108a862940Sderaadt const struct {
1118a862940Sderaadt 	const struct space_allocation *table;
1128a862940Sderaadt 	int sz;
1138a862940Sderaadt } alloc_table[] = {
1148dde8bb6Sotto 	{ alloc_big,	nitems(alloc_big) },
1158dde8bb6Sotto 	{ alloc_medium,	nitems(alloc_medium) },
1168dde8bb6Sotto 	{ alloc_small,	nitems(alloc_small) },
1178dde8bb6Sotto 	{ alloc_stupid,	nitems(alloc_stupid) }
118557f712bSkrw };
119557f712bSkrw 
1209fdcb4d6Skrw void	edit_parms(struct disklabel *);
1216aaa4aabSotto void	editor_resize(struct disklabel *, char *);
12234ae4198Skrw void	editor_add(struct disklabel *, char *);
1239fdcb4d6Skrw void	editor_change(struct disklabel *, char *);
1249fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *);
12534ae4198Skrw void	editor_delete(struct disklabel *, char *);
1264d812bb6Slum void	editor_help(void);
12734ae4198Skrw void	editor_modify(struct disklabel *, char *);
12834ae4198Skrw void	editor_name(struct disklabel *, char *);
129c72b5b24Smillert char	*getstring(char *, char *, char *);
130dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int);
1311f0f871dSkrw int	has_overlap(struct disklabel *);
132c72b5b24Smillert int	partition_cmp(const void *, const void *);
1330fbd3c97Skrw struct partition **sort_partitions(struct disklabel *);
134c72b5b24Smillert void	getdisktype(struct disklabel *, char *, char *);
13587023ed9Skrw void	find_bounds(struct disklabel *);
1369fdcb4d6Skrw void	set_bounds(struct disklabel *);
13769a6ffbcSjsing void	set_duid(struct disklabel *);
138c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *);
1394f3bbbf0Skrw void	mpcopy(char **, char **);
140c72b5b24Smillert int	micmp(const void *, const void *);
141c72b5b24Smillert int	mpequal(char **, char **);
142c72b5b24Smillert int	get_bsize(struct disklabel *, int);
143c72b5b24Smillert int	get_fsize(struct disklabel *, int);
144c72b5b24Smillert int	get_fstype(struct disklabel *, int);
14534ae4198Skrw int	get_mp(struct disklabel *, int);
146604d3bdeSkrw int	get_offset(struct disklabel *, int);
1479fdcb4d6Skrw int	get_size(struct disklabel *, int);
14887023ed9Skrw void	get_geometry(int, struct disklabel **);
14987023ed9Skrw void	set_geometry(struct disklabel *, struct disklabel *, struct disklabel *,
15087023ed9Skrw 	    char *);
1519fdcb4d6Skrw void	zero_partitions(struct disklabel *);
15214192793Skrw u_int64_t max_partition_size(struct disklabel *, int);
15334ae4198Skrw void	display_edit(struct disklabel *, char, u_int64_t);
15496a888c6Smillert 
1551e0ad43cSotto static u_int64_t starting_sector;
1561e0ad43cSotto static u_int64_t ending_sector;
1572d8451b0Smillert static int expert;
158fc6e9c48Sotto static int overlap;
1596fe57b42Smillert 
1606fe57b42Smillert /*
1614d4a335eSkrw  * Simple partition editor.
1626fe57b42Smillert  */
1636fe57b42Smillert int
164d6d80bb0Skrw editor(int f)
1656fe57b42Smillert {
166d6d80bb0Skrw 	struct disklabel origlabel, lastlabel, tmplabel, newlab = lab;
1677e28fb0fSderaadt 	struct disklabel *disk_geop = NULL;
16896a888c6Smillert 	struct partition *pp;
1696fe57b42Smillert 	FILE *fp;
1706fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
17134ae4198Skrw 	char **omountpoints = NULL;
1724f3bbbf0Skrw 	char **origmountpoints = NULL, **tmpmountpoints = NULL;
1737e28fb0fSderaadt 	int i, error = 0;
174bd6726faSmillert 
175bd6726faSmillert 	/* Alloc and init mount point info */
17634ae4198Skrw 	if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
1774f3bbbf0Skrw 	    !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
178bd6726faSmillert 	    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
179bd6726faSmillert 		errx(4, "out of memory");
1806fe57b42Smillert 
18196a888c6Smillert 	/* Don't allow disk type of "unknown" */
182d6d80bb0Skrw 	getdisktype(&newlab, "You need to specify a type for this disk.", specname);
1836fe57b42Smillert 
18487023ed9Skrw 	/* Get the on-disk geometries if possible */
18587023ed9Skrw 	get_geometry(f, &disk_geop);
186c33fcabaSmillert 
187d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
188d6d80bb0Skrw 	find_bounds(&newlab);
189d09f3941Smillert 
19096a888c6Smillert 	/* Make sure there is no partition overlap. */
191d6d80bb0Skrw 	if (has_overlap(&newlab))
1926fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1936fe57b42Smillert 
19496a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
195d6d80bb0Skrw 	pp = &newlab.d_partitions[RAW_PART];
196d6d80bb0Skrw 	if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) {
19796a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
198d6d80bb0Skrw 		if (newlab.d_npartitions < 3)
199d6d80bb0Skrw 			newlab.d_npartitions = 3;
20034af67a3Sotto 		DL_SETPOFFSET(pp, 0);
201d6d80bb0Skrw 		DL_SETPSIZE(pp, DL_GETDSIZE(&newlab));
20296a888c6Smillert 		pp->p_fstype = FS_UNUSED;
203ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
20496a888c6Smillert 	}
2050f820bbbSmillert 
206fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
207d6d80bb0Skrw 	if (newlab.d_flags & D_VENDOR) {
208fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
209fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
210fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
211fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
212fc1a4cc6Sderaadt 	}
2136fe57b42Smillert #endif
2146fe57b42Smillert 
215bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
216d6d80bb0Skrw 	if (newlab.d_bbsize == 0)
217d6d80bb0Skrw 		newlab.d_bbsize = BBSIZE;
218d6d80bb0Skrw 	if (newlab.d_sbsize == 0)
219d6d80bb0Skrw 		newlab.d_sbsize = SBSIZE;
220f98aebd4Smillert 
22193160b9bSkrw 	/* Save the (U|u)ndo labels and mountpoints. */
22293160b9bSkrw 	mpcopy(origmountpoints, mountpoints);
223d6d80bb0Skrw 	origlabel = newlab;
224d6d80bb0Skrw 	lastlabel = newlab;
22534ae4198Skrw 
22634ae4198Skrw 	puts("Label editor (enter '?' for help at any prompt)");
2276fe57b42Smillert 	for (;;) {
2286fe57b42Smillert 		fputs("> ", stdout);
2296e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2306e0becc5Smillert 			putchar('\n');
2316e0becc5Smillert 			buf[0] = 'q';
2326e0becc5Smillert 			buf[1] = '\0';
2336e0becc5Smillert 		}
234260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
235260513deSmillert 			continue;
236260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2376fe57b42Smillert 
2384f3bbbf0Skrw 		if ((*cmd != 'u') && (*cmd != 'U')) {
2394f3bbbf0Skrw 			/*
2404f3bbbf0Skrw 			 * Save undo info in case the command tries to make
2414f3bbbf0Skrw 			 * changes but decides not to.
2424f3bbbf0Skrw 			 */
2434f3bbbf0Skrw 			tmplabel = lastlabel;
244d6d80bb0Skrw 			lastlabel = newlab;
2454f3bbbf0Skrw 			mpcopy(tmpmountpoints, omountpoints);
2464f3bbbf0Skrw 			mpcopy(omountpoints, mountpoints);
2474f3bbbf0Skrw 		}
2486fe57b42Smillert 
2494f3bbbf0Skrw 		switch (*cmd) {
2506fe57b42Smillert 		case '?':
251ea37abd3Sderaadt 		case 'h':
2524d812bb6Slum 			editor_help();
2536fe57b42Smillert 			break;
2546fe57b42Smillert 
255557f712bSkrw 		case 'A':
256d6d80bb0Skrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == 0) {
257ab20a3eaSkrw 				aflag = 1;
258d6d80bb0Skrw 				editor_allocspace(&newlab);
259ab20a3eaSkrw 			} else
260d6d80bb0Skrw 				newlab = lastlabel;
261557f712bSkrw 			break;
2626fe57b42Smillert 		case 'a':
263d6d80bb0Skrw 			editor_add(&newlab, arg);
26496a888c6Smillert 			break;
26596a888c6Smillert 
26696a888c6Smillert 		case 'b':
267d6d80bb0Skrw 			set_bounds(&newlab);
2686fe57b42Smillert 			break;
2696fe57b42Smillert 
2706fe57b42Smillert 		case 'c':
271d6d80bb0Skrw 			editor_change(&newlab, arg);
2726fe57b42Smillert 			break;
2736fe57b42Smillert 
2749afbe9eeSmillert 		case 'D':
275d6d80bb0Skrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == 0) {
27671bba4ecSkrw 				dflag = 1;
27793160b9bSkrw 				for (i=0; i<MAXPARTITIONS; i++) {
27893160b9bSkrw 					free(mountpoints[i]);
27993160b9bSkrw 					mountpoints[i] = NULL;
28093160b9bSkrw 				}
28193160b9bSkrw 			} else
282cdd7eb76Smillert 				warn("unable to get default partition table");
2839afbe9eeSmillert 			break;
2849afbe9eeSmillert 
2856fe57b42Smillert 		case 'd':
286d6d80bb0Skrw 			editor_delete(&newlab, arg);
2876fe57b42Smillert 			break;
2886fe57b42Smillert 
2899afbe9eeSmillert 		case 'e':
290d6d80bb0Skrw 			edit_parms(&newlab);
2919afbe9eeSmillert 			break;
2929afbe9eeSmillert 
293c33fcabaSmillert 		case 'g':
294d6d80bb0Skrw 			set_geometry(&newlab, disk_geop, &lab, arg);
295c33fcabaSmillert 			break;
296c33fcabaSmillert 
2970d63cfbaSjsing 		case 'i':
298d6d80bb0Skrw 			set_duid(&newlab);
2990d63cfbaSjsing 			break;
3000d63cfbaSjsing 
3016fe57b42Smillert 		case 'm':
302d6d80bb0Skrw 			editor_modify(&newlab, arg);
303bd6726faSmillert 			break;
304bd6726faSmillert 
305bd6726faSmillert 		case 'n':
3065c79e1cfSkrw 			if (!fstabfile) {
307bd6726faSmillert 				fputs("This option is not valid when run "
30884d0bb16Sderaadt 				    "without the -f flag.\n", stderr);
309bd6726faSmillert 				break;
310bd6726faSmillert 			}
311d6d80bb0Skrw 			editor_name(&newlab, arg);
3126fe57b42Smillert 			break;
3136fe57b42Smillert 
3146fe57b42Smillert 		case 'p':
315d6d80bb0Skrw 			display_edit(&newlab, arg ? *arg : 0,
316d6d80bb0Skrw 			    editor_countfree(&newlab));
3176fe57b42Smillert 			break;
3186fe57b42Smillert 
319aff3f969Sotto 		case 'l':
320d6d80bb0Skrw 			display(stdout, &newlab, arg ? *arg : 0, 0);
321aff3f969Sotto 			break;
322aff3f969Sotto 
323508086e9Smillert 		case 'M': {
324508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
32545decb36Sderaadt 			char *pager, *comm = NULL;
326e7936562Sderaadt 			extern const u_char manpage[];
32708f8e31fSotto 			extern const int manpage_sz;
3285d12b01bSderaadt 
329489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
330508086e9Smillert 				pager = _PATH_LESS;
33108f8e31fSotto 
33245decb36Sderaadt 			if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
33345decb36Sderaadt 			    (fp = popen(comm, "w")) != NULL) {
33408f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3355d12b01bSderaadt 				pclose(fp);
336508086e9Smillert 			} else
337508086e9Smillert 				warn("unable to execute %s", pager);
338508086e9Smillert 
33945decb36Sderaadt 			free(comm);
340508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3415d12b01bSderaadt 			break;
342508086e9Smillert 		}
3435d12b01bSderaadt 
3446fe57b42Smillert 		case 'q':
34569220492Smillert 			if (donothing) {
34669220492Smillert 				puts("In no change mode, not writing label.");
3477e28fb0fSderaadt 				goto done;
34869220492Smillert 			}
34993160b9bSkrw 
35071bba4ecSkrw                         /*
35193160b9bSkrw 			 * If we haven't changed the original label, and it
35293160b9bSkrw 			 * wasn't a default label or an auto-allocated label,
35393160b9bSkrw 			 * there is no need to do anything before exiting. Note
35493160b9bSkrw 			 * that 'w' will reset dflag and aflag to allow 'q' to
35593160b9bSkrw 			 * exit without further questions.
35671bba4ecSkrw 			 */
357ab20a3eaSkrw 			if (!dflag && !aflag &&
358d6d80bb0Skrw 			    memcmp(&lab, &newlab, sizeof(newlab)) == 0) {
359bd6726faSmillert 				puts("No label changes.");
360d6d80bb0Skrw 				/* Save mountpoint info. */
361d6d80bb0Skrw 				mpsave(&newlab);
3627e28fb0fSderaadt 				goto done;
3636fe57b42Smillert 			}
3646fe57b42Smillert 			do {
365d0e67762Smillert 				arg = getstring("Write new label?",
366d0e67762Smillert 				    "Write the modified label to disk?",
367d0e67762Smillert 				    "y");
36896a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
36996a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
370d6d80bb0Skrw 				if (writelabel(f, bootarea, &newlab) == 0) {
371d6d80bb0Skrw 					newlab = lab; /* lab now has UID info */
3727e28fb0fSderaadt 					goto done;
3736fe57b42Smillert 				}
374d0e67762Smillert 				warnx("unable to write label");
375d0e67762Smillert 			}
3767e28fb0fSderaadt 			error = 1;
3777e28fb0fSderaadt 			goto done;
3786fe57b42Smillert 			/* NOTREACHED */
3796fe57b42Smillert 			break;
3806fe57b42Smillert 
3816aaa4aabSotto 		case 'R':
382fc6e9c48Sotto 			if (aflag && !overlap)
383d6d80bb0Skrw 				editor_resize(&newlab, arg);
3846aaa4aabSotto 			else
3856aaa4aabSotto 				fputs("Resize only implemented for auto "
386fc6e9c48Sotto 				    "allocated labels\n", stderr);
3876aaa4aabSotto 			break;
3886aaa4aabSotto 
38925f9c360Skrw 		case 'r': {
39025f9c360Skrw 			struct diskchunk *chunks;
39125f9c360Skrw 			int i;
3929fdcb4d6Skrw 			/* Display free space. */
393d6d80bb0Skrw 			chunks = free_chunks(&newlab);
39425f9c360Skrw 			for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0;
39525f9c360Skrw 			    i++)
39625f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
39725f9c360Skrw 				    "(%16llu)\n",
39825f9c360Skrw 				    chunks[i].start, chunks[i].stop - 1,
39925f9c360Skrw 				    chunks[i].stop - chunks[i].start);
40025f9c360Skrw 			fprintf(stderr, "Total free sectors: %llu.\n",
401d6d80bb0Skrw 			    editor_countfree(&newlab));
402c0bdc608Smillert 			break;
40325f9c360Skrw 		}
404c0bdc608Smillert 
4056fe57b42Smillert 		case 's':
4066fe57b42Smillert 			if (arg == NULL) {
407c33fcabaSmillert 				arg = getstring("Filename",
4086fe57b42Smillert 				    "Name of the file to save label into.",
4096fe57b42Smillert 				    NULL);
410e97229a3Scnst 				if (arg == NULL || *arg == '\0')
4116fe57b42Smillert 					break;
4126fe57b42Smillert 			}
4136fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
4146fe57b42Smillert 				warn("cannot open %s", arg);
4156fe57b42Smillert 			} else {
416d6d80bb0Skrw 				display(fp, &newlab, 0, 1);
4176fe57b42Smillert 				(void)fclose(fp);
4186fe57b42Smillert 			}
4196fe57b42Smillert 			break;
4206fe57b42Smillert 
4214f3bbbf0Skrw 		case 'U':
42293160b9bSkrw 			/*
42393160b9bSkrw 			 * If we allow 'U' repeatedly, information would be lost. This way
42493160b9bSkrw 			 * multiple 'U's followed by 'u' would undo the 'U's.
42593160b9bSkrw 			 */
426d6d80bb0Skrw 			if (memcmp(&newlab, &origlabel, sizeof(newlab)) ||
42793160b9bSkrw 			    !mpequal(mountpoints, origmountpoints)) {
428d6d80bb0Skrw 				tmplabel = newlab;
429d6d80bb0Skrw 				newlab = origlabel;
4304f3bbbf0Skrw 				lastlabel = tmplabel;
4314f3bbbf0Skrw 				mpcopy(tmpmountpoints, mountpoints);
4324f3bbbf0Skrw 				mpcopy(mountpoints, origmountpoints);
4334f3bbbf0Skrw 				mpcopy(omountpoints, tmpmountpoints);
4344f3bbbf0Skrw 			}
43593160b9bSkrw 			puts("Original label and mount points restored.");
4364f3bbbf0Skrw 			break;
4374f3bbbf0Skrw 
4386fe57b42Smillert 		case 'u':
439d6d80bb0Skrw 			tmplabel = newlab;
440d6d80bb0Skrw 			newlab = lastlabel;
4416fe57b42Smillert 			lastlabel = tmplabel;
4424f3bbbf0Skrw 			mpcopy(tmpmountpoints, mountpoints);
443bd6726faSmillert 			mpcopy(mountpoints, omountpoints);
4444f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4456fe57b42Smillert 			puts("Last change undone.");
4466fe57b42Smillert 			break;
4476fe57b42Smillert 
448040947cfSmillert 		case 'w':
449bd6726faSmillert 			if (donothing)  {
450040947cfSmillert 				puts("In no change mode, not writing label.");
451bd6726faSmillert 				break;
452bd6726faSmillert 			}
45393160b9bSkrw 
45441f684b9Skrw 			/* Write label to disk. */
455d6d80bb0Skrw 			if (writelabel(f, bootarea, &newlab) != 0)
456040947cfSmillert 				warnx("unable to write label");
45771bba4ecSkrw 			else {
458ab20a3eaSkrw 				dflag = aflag = 0;
459d6d80bb0Skrw 				newlab = lab; /* lab now has UID info */
46071bba4ecSkrw 			}
461040947cfSmillert 			break;
462040947cfSmillert 
4632d8451b0Smillert 		case 'X':
4642d8451b0Smillert 			expert = !expert;
4652d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
4662d8451b0Smillert 			    "Exiting");
4672d8451b0Smillert 			break;
4682d8451b0Smillert 
4696fe57b42Smillert 		case 'x':
4707e28fb0fSderaadt 			goto done;
4716fe57b42Smillert 			break;
4726fe57b42Smillert 
4739afbe9eeSmillert 		case 'z':
474d6d80bb0Skrw 			zero_partitions(&newlab);
4756fe57b42Smillert 			break;
4766fe57b42Smillert 
4779afbe9eeSmillert 		case '\n':
4786fe57b42Smillert 			break;
4796fe57b42Smillert 
4806fe57b42Smillert 		default:
4816fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4826fe57b42Smillert 			break;
4836fe57b42Smillert 		}
4844f3bbbf0Skrw 
4854f3bbbf0Skrw 		/*
4864f3bbbf0Skrw 		 * If no changes were made to label or mountpoints, then
4874f3bbbf0Skrw 		 * restore undo info.
4884f3bbbf0Skrw 		 */
489d6d80bb0Skrw 		if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 &&
49093160b9bSkrw 		    (mpequal(mountpoints, omountpoints))) {
4914f3bbbf0Skrw 			lastlabel = tmplabel;
4924f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4934f3bbbf0Skrw 		}
4946fe57b42Smillert 	}
4957e28fb0fSderaadt done:
4967e28fb0fSderaadt 	free(omountpoints);
4977e28fb0fSderaadt 	free(origmountpoints);
4987e28fb0fSderaadt 	free(tmpmountpoints);
4997e28fb0fSderaadt 	if (disk_geop)
5007e28fb0fSderaadt 		free(disk_geop);
5017e28fb0fSderaadt 	return(error);
5026fe57b42Smillert }
5036fe57b42Smillert 
5048dde8bb6Sotto int64_t
5058dde8bb6Sotto getphysmem(void)
5068dde8bb6Sotto {
5078dde8bb6Sotto 	int64_t physmem;
5088dde8bb6Sotto 	size_t sz = sizeof(physmem);
5098dde8bb6Sotto 	int mib[] = { CTL_HW, HW_PHYSMEM64 };
5108dde8bb6Sotto 	if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1)
5118dde8bb6Sotto 		errx(4, "can't get mem size");
5128dde8bb6Sotto 	return physmem;
5138dde8bb6Sotto }
5148dde8bb6Sotto 
5156fe57b42Smillert /*
516557f712bSkrw  * Allocate all disk space according to standard recommendations for a
517557f712bSkrw  * root disk.
518557f712bSkrw  */
519557f712bSkrw void
5208dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
521557f712bSkrw {
5228dde8bb6Sotto 	struct disklabel *lp, label;
5238dde8bb6Sotto 	struct space_allocation *alloc;
52434ae4198Skrw 	struct space_allocation *ap;
525557f712bSkrw 	struct partition *pp;
52634ae4198Skrw 	struct diskchunk *chunks;
52734ae4198Skrw 	daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs;
52834ae4198Skrw 	char **partmp;
529a49bdda8Skrw 	int i, j, lastalloc, index = 0, fragsize, partno;
5308dde8bb6Sotto 	int64_t physmem;
5318dde8bb6Sotto 
53234ae4198Skrw 	/* How big is the OpenBSD portion of the disk?  */
5338dde8bb6Sotto 	find_bounds(lp_org);
534557f712bSkrw 
535fc6e9c48Sotto 	overlap = 0;
536fc6e9c48Sotto 	for (i = 0;  i < MAXPARTITIONS; i++) {
537fc6e9c48Sotto 		daddr64_t psz, pstart, pend;
538fc6e9c48Sotto 
539fc6e9c48Sotto 		pp = &lp_org->d_partitions[i];
540fc6e9c48Sotto 		psz = DL_GETPSIZE(pp);
541fc6e9c48Sotto 		pstart = DL_GETPOFFSET(pp);
542fc6e9c48Sotto 		pend = pstart + psz;
543fc6e9c48Sotto 		if (i != RAW_PART && psz != 0 &&
544fc6e9c48Sotto 		    ((pstart >= starting_sector && pstart <= ending_sector) ||
545fc6e9c48Sotto 		    (pend > starting_sector && pend < ending_sector))) {
546fc6e9c48Sotto 			overlap = 1;
547fc6e9c48Sotto 			break;
548fc6e9c48Sotto 		}
549fc6e9c48Sotto 	}
550fc6e9c48Sotto 
551fc6e9c48Sotto 	physmem = getphysmem() / lp_org->d_secsize;
552fc6e9c48Sotto 
5538dde8bb6Sotto 	cylsecs = lp_org->d_secpercyl;
5548dde8bb6Sotto again:
5558dde8bb6Sotto 	lp = &label;
5563d98fc8cSkrw 	for (i=0; i<MAXPARTITIONS; i++) {
5573d98fc8cSkrw 		free(mountpoints[i]);
5583d98fc8cSkrw 		mountpoints[i] = NULL;
5593d98fc8cSkrw 	}
5608dde8bb6Sotto 	memcpy(lp, lp_org, sizeof(struct disklabel));
5610a7398ceSderaadt 	lp->d_npartitions = MAXPARTITIONS;
5628dde8bb6Sotto 	lastalloc = alloc_table[index].sz;
5638dde8bb6Sotto 	alloc = malloc(lastalloc * sizeof(struct space_allocation));
5648dde8bb6Sotto 	if (alloc == NULL)
5658dde8bb6Sotto 		errx(4, "out of memory");
5668dde8bb6Sotto 	memcpy(alloc, alloc_table[index].table,
5678dde8bb6Sotto 	    lastalloc * sizeof(struct space_allocation));
5688dde8bb6Sotto 
5698dde8bb6Sotto 	/* bump max swap based on phys mem, little physmem gets 2x swap */
5708dde8bb6Sotto 	if (index == 0) {
5718dde8bb6Sotto 		if (physmem < 256LL * 1024 * 1024 / lp->d_secsize)
5728dde8bb6Sotto 			alloc[1].maxsz = 2 * physmem;
5738dde8bb6Sotto 		else
5748dde8bb6Sotto 			alloc[1].maxsz += physmem;
5758dde8bb6Sotto 		/* bump max /var to make room for 2 crash dumps */
5768dde8bb6Sotto 		alloc[3].maxsz += 2 * physmem;
5778dde8bb6Sotto 	}
5788dde8bb6Sotto 
57934ae4198Skrw 	xtrasecs = totsecs = editor_countfree(lp);
580557f712bSkrw 
58134ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
5825f3e1104Skrw 		alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz);
5835f3e1104Skrw 		alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz);
58434ae4198Skrw 		if (xtrasecs > alloc[i].minsz)
58534ae4198Skrw 			xtrasecs -= alloc[i].minsz;
58634ae4198Skrw 		else
58734ae4198Skrw 			xtrasecs = 0;
588557f712bSkrw 	}
589557f712bSkrw 
59034ae4198Skrw 	for (i = 0; i < lastalloc; i++) {
59134ae4198Skrw 		/* Find next available partition. */
59234ae4198Skrw 		for (j = 0;  j < MAXPARTITIONS; j++)
59334ae4198Skrw 			if (DL_GETPSIZE(&lp->d_partitions[j]) == 0)
59434ae4198Skrw 				break;
595a243d7b5Skrw 		if (j == MAXPARTITIONS) {
596a243d7b5Skrw 			/* It did not work out, try next strategy */
597a243d7b5Skrw 			free(alloc);
598a243d7b5Skrw 			if (++index < nitems(alloc_table))
599a243d7b5Skrw 				goto again;
600a243d7b5Skrw 			else
60134ae4198Skrw 				return;
602a243d7b5Skrw 		}
603a49bdda8Skrw 		partno = j;
60434ae4198Skrw 		pp = &lp->d_partitions[j];
60534ae4198Skrw 		partmp = &mountpoints[j];
60634ae4198Skrw 		ap = &alloc[i];
607557f712bSkrw 
60834ae4198Skrw 		/* Figure out the size of the partition. */
60934ae4198Skrw 		if (i == lastalloc - 1) {
61034ae4198Skrw 			if (totsecs > ap->maxsz)
61134ae4198Skrw 				secs = ap->maxsz;
612557f712bSkrw 			else
6135f3e1104Skrw 				secs = totsecs;
6141f5ea549Skrw #ifdef SUN_CYLCHECK
6151f5ea549Skrw 			goto cylinderalign;
6161f5ea549Skrw #endif
617557f712bSkrw 		} else {
61834ae4198Skrw 			secs = ap->minsz;
6195f3e1104Skrw 			if (xtrasecs > 0)
62034ae4198Skrw 				secs += (xtrasecs / 100) * ap->rate;
62134ae4198Skrw 			if (secs > ap->maxsz)
62234ae4198Skrw 				secs = ap->maxsz;
6231f5ea549Skrw #ifdef SUN_CYLCHECK
6241f5ea549Skrw cylinderalign:
6255f3e1104Skrw 			secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
6261f5ea549Skrw #endif
6275f3e1104Skrw 			totsecs -= secs;
6281f5ea549Skrw #ifdef SUN_CYLCHECK
6295f3e1104Skrw 			while (totsecs < 0) {
6305f3e1104Skrw 				secs -= cylsecs;
6315f3e1104Skrw 				totsecs += cylsecs;
632557f712bSkrw 			}
6331f5ea549Skrw #endif
634557f712bSkrw 		}
63534ae4198Skrw 
63634ae4198Skrw 		/* Find largest chunk of free space. */
63734ae4198Skrw 		chunks = free_chunks(lp);
63834ae4198Skrw 		chunkstart = 0;
63934ae4198Skrw 		chunksize = 0;
64034ae4198Skrw 		for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++)
64134ae4198Skrw 			if ((chunks[j].stop - chunks[j].start) > chunksize) {
64234ae4198Skrw 				chunkstart = chunks[j].start;
64334ae4198Skrw 				chunksize = chunks[j].stop - chunks[j].start;
644557f712bSkrw 			}
64534ae4198Skrw #ifdef SUN_CYLCHECK
64634ae4198Skrw 		if (lp->d_flags & D_VENDOR) {
64734ae4198Skrw 			/* Align chunk to cylinder boundaries. */
64834ae4198Skrw 			chunksize -= chunksize % cylsecs;
6496ab0bb66Skrw 			chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) *
6506ab0bb66Skrw 			    cylsecs;
65134ae4198Skrw 		}
65234ae4198Skrw #endif
65334ae4198Skrw 		/* See if partition can fit into chunk. */
65434ae4198Skrw 		if (secs > chunksize) {
65534ae4198Skrw 			totsecs += secs - chunksize;
65634ae4198Skrw 			secs = chunksize;
65734ae4198Skrw 		}
65834ae4198Skrw 		if (secs < ap->minsz) {
6598dde8bb6Sotto 			/* It did not work out, try next strategy */
6608dde8bb6Sotto 			free(alloc);
6618dde8bb6Sotto 			if (++index < nitems(alloc_table))
6628dde8bb6Sotto 				goto again;
6638dde8bb6Sotto 			else
6648dde8bb6Sotto 				return;
665557f712bSkrw 		}
66634ae4198Skrw 
66734ae4198Skrw 		/* Everything seems ok so configure the partition. */
6685f3e1104Skrw 		DL_SETPSIZE(pp, secs);
66934ae4198Skrw 		DL_SETPOFFSET(pp, chunkstart);
670ef93a5eeSkrw 		fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 :
671ef93a5eeSkrw 		    lp->d_secsize;
672c88f83bdSotto 		if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024)
673c88f83bdSotto 			fragsize *= 2;
674c88f83bdSotto 		if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024)
675c88f83bdSotto 			fragsize *= 2;
676557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__)
677557f712bSkrw 		/* can't boot from > 8k boot blocks */
678557f712bSkrw 		pp->p_fragblock =
6796e312d52Sotto 		    DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8);
680557f712bSkrw #else
6816e312d52Sotto 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
682557f712bSkrw #endif
683557f712bSkrw 		pp->p_cpg = 1;
68434ae4198Skrw 		if (ap->mp[0] != '/')
68534ae4198Skrw 			pp->p_fstype = FS_SWAP;
68634ae4198Skrw 		else {
68734ae4198Skrw 			pp->p_fstype = FS_BSDFFS;
688a49bdda8Skrw 			get_bsize(lp, partno);
68934ae4198Skrw 			free(*partmp);
69034ae4198Skrw 			if ((*partmp = strdup(ap->mp)) == NULL)
691557f712bSkrw 				errx(4, "out of memory");
692557f712bSkrw 		}
693557f712bSkrw 	}
694557f712bSkrw 
6958dde8bb6Sotto 	free(alloc);
6968dde8bb6Sotto 	memcpy(lp_org, lp, sizeof(struct disklabel));
697557f712bSkrw }
698557f712bSkrw 
699557f712bSkrw /*
7006aaa4aabSotto  * Resize a partition, moving all subsequent partitions
7016aaa4aabSotto  */
7026aaa4aabSotto void
7036aaa4aabSotto editor_resize(struct disklabel *lp, char *p)
7046aaa4aabSotto {
7056aaa4aabSotto 	struct disklabel label;
7066aaa4aabSotto 	struct partition *pp, *prev;
7076aaa4aabSotto 	daddr64_t secs, sz, off;
7086aaa4aabSotto #ifdef SUN_CYLCHECK
7096aaa4aabSotto 	daddr64_t cylsecs;
7106aaa4aabSotto #endif
7116aaa4aabSotto 	int partno, i;
7126aaa4aabSotto 
7136aaa4aabSotto 	label = *lp;
7146aaa4aabSotto 
7156aaa4aabSotto 	/* Change which partition? */
7166aaa4aabSotto 	if (p == NULL) {
7176aaa4aabSotto 		p = getstring("partition to resize",
7186aaa4aabSotto 		    "The letter of the partition to name, a - p.", NULL);
7196aaa4aabSotto 	}
7206aaa4aabSotto 	if (p == NULL) {
7216aaa4aabSotto 		fputs("Command aborted\n", stderr);
7226aaa4aabSotto 		return;
7236aaa4aabSotto 	}
7246aaa4aabSotto 	partno = p[0] - 'a';
7256aaa4aabSotto         if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
7266aaa4aabSotto 		fprintf(stderr, "Partition must be between 'a' and '%c' "
7276aaa4aabSotto 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
7286aaa4aabSotto 		return;
7296aaa4aabSotto 	}
7306aaa4aabSotto 
7316aaa4aabSotto 	pp = &label.d_partitions[partno];
732fc6e9c48Sotto 	sz = DL_GETPSIZE(pp);
733fc6e9c48Sotto 	if (sz == 0) {
734fc6e9c48Sotto 		fputs("No such partition\n", stderr);
735fc6e9c48Sotto 		return;
736fc6e9c48Sotto 	}
737fc6e9c48Sotto 	if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) {
738fc6e9c48Sotto 		fputs("Cannot resize spoofed partition\n", stderr);
739fc6e9c48Sotto 		return;
740fc6e9c48Sotto 	}
7414659aa0dSotto 	secs = getuint(lp, "[+|-]new size (with unit)",
7424659aa0dSotto 	    "new size or amount to grow (+) or shrink (-) partition including unit",
7434659aa0dSotto 	    sz, editor_countfree(lp), 0, DO_CONVERSIONS);
7446aaa4aabSotto 
7454659aa0dSotto 	if (secs <= 0) {
7466aaa4aabSotto 		fputs("Command aborted\n", stderr);
7476aaa4aabSotto 		return;
7486aaa4aabSotto 	}
7496aaa4aabSotto 
7506aaa4aabSotto #ifdef SUN_CYLCHECK
7516aaa4aabSotto 	cylsecs = lp->d_secpercyl;
7526aaa4aabSotto 	if (secs > 0)
7536aaa4aabSotto 		secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs;
7546aaa4aabSotto 	else
7556aaa4aabSotto 		secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs;
7566aaa4aabSotto #endif
7574659aa0dSotto 	if (DL_GETPOFFSET(pp) + secs > ending_sector) {
7586aaa4aabSotto 		fputs("Amount too big\n", stderr);
7596aaa4aabSotto 		return;
7606aaa4aabSotto 	}
7616aaa4aabSotto 
7624659aa0dSotto 	DL_SETPSIZE(pp, secs);
763e5f81948Sotto 	get_bsize(&label, partno);
7646aaa4aabSotto 
7656aaa4aabSotto 	/*
7666aaa4aabSotto 	 * Pack partitions above the resized partition, leaving unused
7676aaa4aabSotto 	 * partions alone.
7686aaa4aabSotto 	 */
7696aaa4aabSotto 	prev = pp;
7706aaa4aabSotto 	for (i = partno + 1; i < MAXPARTITIONS; i++) {
7716aaa4aabSotto 		if (i == RAW_PART)
7726aaa4aabSotto 			continue;
773fc6e9c48Sotto 		pp = &label.d_partitions[i];
774fc6e9c48Sotto 		if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP)
775fc6e9c48Sotto 			continue;
776fc6e9c48Sotto 		sz = DL_GETPSIZE(pp);
7776aaa4aabSotto 		if (sz == 0)
7786aaa4aabSotto 			continue;
7796aaa4aabSotto 
7806aaa4aabSotto 		off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
7816aaa4aabSotto 
7826aaa4aabSotto 		if (off < ending_sector) {
7836aaa4aabSotto 			DL_SETPOFFSET(pp, off);
7846aaa4aabSotto 			if (off + DL_GETPSIZE(pp) > ending_sector) {
7856aaa4aabSotto 				DL_SETPSIZE(pp, ending_sector - off);
7866aaa4aabSotto 				fprintf(stderr,
7876aaa4aabSotto 				    "Partition %c shrunk to make room\n",
7886aaa4aabSotto 				    i + 'a');
7896aaa4aabSotto 			}
7906aaa4aabSotto 		} else {
7916aaa4aabSotto 			fputs("No room left for all partitions\n", stderr);
7926aaa4aabSotto 			return;
7936aaa4aabSotto 		}
794e5f81948Sotto 		get_bsize(&label, i);
7956aaa4aabSotto 		prev = pp;
7966aaa4aabSotto 	}
7976aaa4aabSotto 	*lp = label;
7986aaa4aabSotto }
7996aaa4aabSotto 
8006aaa4aabSotto /*
8016fe57b42Smillert  * Add a new partition.
8026fe57b42Smillert  */
8036fe57b42Smillert void
80434ae4198Skrw editor_add(struct disklabel *lp, char *p)
8056fe57b42Smillert {
80696a888c6Smillert 	struct partition *pp;
80796a888c6Smillert 	struct diskchunk *chunks;
8085caa08b2Skrw 	char buf[2];
8096e312d52Sotto 	int i, partno, fragsize;
810f8ab7229Schl 	u_int64_t freesectors, new_offset, new_size;
8119fdcb4d6Skrw 
8129fdcb4d6Skrw 	freesectors = editor_countfree(lp);
8136fe57b42Smillert 
8146fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
815fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
8169fdcb4d6Skrw 	if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) {
817fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
818fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
819fc1a4cc6Sderaadt 		    stderr);
820fc1a4cc6Sderaadt 		return;
821fc1a4cc6Sderaadt 	}
8228390cf28Smillert #endif
8239fdcb4d6Skrw 	if (freesectors == 0) {
8246fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
8256fe57b42Smillert 		    stderr);
8266fe57b42Smillert 		return;
8276fe57b42Smillert 	}
8286fe57b42Smillert 
8295caa08b2Skrw 	if (p == NULL) {
8305caa08b2Skrw 		/*
8315caa08b2Skrw 		 * Use the first unused partition that is not 'c' as the
8325caa08b2Skrw 		 * default partition in the prompt string.
8335caa08b2Skrw 		 */
8345caa08b2Skrw 		pp = &lp->d_partitions[0];
8355caa08b2Skrw 		buf[0] = buf[1] = '\0';
8365caa08b2Skrw 		for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) {
8375caa08b2Skrw 			if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) {
8385caa08b2Skrw 				buf[0] = partno + 'a';
8395caa08b2Skrw 				p = &buf[0];
8406fe57b42Smillert 				break;
8416fe57b42Smillert 			}
8425caa08b2Skrw 		}
843c33fcabaSmillert 		p = getstring("partition",
8446fe57b42Smillert 		    "The letter of the new partition, a - p.", p);
8456fe57b42Smillert 	}
8465caa08b2Skrw 	if (p == NULL) {
8475caa08b2Skrw 		fputs("Command aborted\n", stderr);
8485caa08b2Skrw 		return;
8495caa08b2Skrw 	}
8505caa08b2Skrw 	partno = p[0] - 'a';
8515caa08b2Skrw 	if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) {
8525caa08b2Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
8535caa08b2Skrw 		    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
8545caa08b2Skrw 		return;
8555caa08b2Skrw 	}
8565caa08b2Skrw 	pp = &lp->d_partitions[partno];
8575caa08b2Skrw 
8585caa08b2Skrw 	if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) {
8595caa08b2Skrw 		fprintf(stderr, "Partition '%c' exists.  Delete it first.\n",
8605caa08b2Skrw 		    p[0]);
8615caa08b2Skrw 		return;
8626fe57b42Smillert 	}
86396a888c6Smillert 
864caf41f96Skrw 	/*
865caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
866855d4e83Ssobrado 	 * zero'ed to avoid inadvertent overlaps.
867caf41f96Skrw 	 */
868caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
869caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
87096a888c6Smillert 
87189f4601dSkrw 	/* Make sure selected partition is zero'd too. */
87289f4601dSkrw 	memset(pp, 0, sizeof(*pp));
87315c15d8aSkrw 	chunks = free_chunks(lp);
87415c15d8aSkrw 
87515c15d8aSkrw 	/*
87615c15d8aSkrw 	 * Since we know there's free space, there must be at least one
87715c15d8aSkrw 	 * chunk. So find the largest chunk and assume we want to add the
87815c15d8aSkrw 	 * partition in that free space.
87915c15d8aSkrw 	 */
88015c15d8aSkrw 	new_size = new_offset = 0;
88115c15d8aSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
88215c15d8aSkrw 		if (chunks[i].stop - chunks[i].start > new_size) {
88315c15d8aSkrw 		    new_size = chunks[i].stop - chunks[i].start;
88415c15d8aSkrw 		    new_offset = chunks[i].start;
88515c15d8aSkrw 		}
88615c15d8aSkrw 	}
8871e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
8881e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
88996a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
890c88f83bdSotto 	pp->p_cpg = 1;
891c88f83bdSotto 
892c88f83bdSotto 	if (get_offset(lp, partno) == 0 &&
893c88f83bdSotto 	    get_size(lp, partno) == 0) {
8946e312d52Sotto 		fragsize = 2048;
895c88f83bdSotto 		new_size = DL_GETPSIZE(pp) * lp->d_secsize;
896c88f83bdSotto 		if (new_size > 128ULL * 1024 * 1024 * 1024)
897c88f83bdSotto 			fragsize *= 2;
898c88f83bdSotto 		if (new_size > 512ULL * 1024 * 1024 * 1024)
899c88f83bdSotto 			fragsize *= 2;
9004a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__)
901d98d4df7Stedu 		/* can't boot from > 8k boot blocks */
902ddfcbf38Sotto 		pp->p_fragblock =
9036e312d52Sotto 		    DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8);
904d98d4df7Stedu #else
9056e312d52Sotto 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8);
906d98d4df7Stedu #endif
907c88f83bdSotto 		if (get_fstype(lp, partno) == 0 &&
90834ae4198Skrw 		    get_mp(lp, partno) == 0 &&
909a4c87e64Skrw 		    get_fsize(lp, partno) == 0  &&
910a4c87e64Skrw 		    get_bsize(lp, partno) == 0)
91196a888c6Smillert 			return;
912c88f83bdSotto 	}
913a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
914da2bd3f5Skrw 	memset(pp, 0, sizeof(*pp));
9156fe57b42Smillert }
9166fe57b42Smillert 
9176fe57b42Smillert /*
918bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
919bd6726faSmillert  */
920bd6726faSmillert void
92134ae4198Skrw editor_name(struct disklabel *lp, char *p)
922bd6726faSmillert {
923bd6726faSmillert 	struct partition *pp;
924bd6726faSmillert 	int partno;
925bd6726faSmillert 
926bd6726faSmillert 	/* Change which partition? */
927bd6726faSmillert 	if (p == NULL) {
928c33fcabaSmillert 		p = getstring("partition to name",
929bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
930bd6726faSmillert 	}
931bd6726faSmillert 	if (p == NULL) {
932bd6726faSmillert 		fputs("Command aborted\n", stderr);
933bd6726faSmillert 		return;
934bd6726faSmillert 	}
935bd6726faSmillert 	partno = p[0] - 'a';
9366c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9376c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9386c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
939bd6726faSmillert 		return;
94066df1f0cSkrw 	}
94166df1f0cSkrw 	pp = &lp->d_partitions[partno];
94266df1f0cSkrw 
94366df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
94466df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
945bd6726faSmillert 		return;
946bd6726faSmillert 	}
947bd6726faSmillert 
948bd6726faSmillert 	/* Not all fstypes can be named */
949bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
950bd387921Stodd 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER ||
951bd387921Stodd 	    pp->p_fstype == FS_RAID) {
952bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
953baa55472Smillert 		    fstypenames[lp->d_partitions[partno].p_fstype]);
954bd6726faSmillert 		return;
955bd6726faSmillert 	}
956bd6726faSmillert 
95734ae4198Skrw 	get_mp(lp, partno);
958bd6726faSmillert }
959bd6726faSmillert 
960bd6726faSmillert /*
9616fe57b42Smillert  * Change an existing partition.
9626fe57b42Smillert  */
9636fe57b42Smillert void
96434ae4198Skrw editor_modify(struct disklabel *lp, char *p)
9656fe57b42Smillert {
9666fe57b42Smillert 	struct partition origpart, *pp;
967f8ab7229Schl 	int partno;
9686fe57b42Smillert 
9696fe57b42Smillert 	/* Change which partition? */
9706fe57b42Smillert 	if (p == NULL) {
971c33fcabaSmillert 		p = getstring("partition to modify",
9726fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
9736fe57b42Smillert 	}
97496a888c6Smillert 	if (p == NULL) {
97596a888c6Smillert 		fputs("Command aborted\n", stderr);
97696a888c6Smillert 		return;
97796a888c6Smillert 	}
9786fe57b42Smillert 	partno = p[0] - 'a';
9796c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
9806c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
9816c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
9826fe57b42Smillert 		return;
98366df1f0cSkrw 	}
98466df1f0cSkrw 	pp = &lp->d_partitions[partno];
98566df1f0cSkrw 
98666df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
98766df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
9886fe57b42Smillert 		return;
9896fe57b42Smillert 	}
9906fe57b42Smillert 
99166df1f0cSkrw 	origpart = *pp;
99266df1f0cSkrw 
993a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
994a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
995a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
99634ae4198Skrw 	    get_mp(lp, partno) == 0 &&
997a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
998a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
99996a888c6Smillert 		return;
10006fe57b42Smillert 
1001a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
1002a4c87e64Skrw 	*pp = origpart;
10036fe57b42Smillert }
10046fe57b42Smillert 
10056fe57b42Smillert /*
10066fe57b42Smillert  * Delete an existing partition.
10076fe57b42Smillert  */
10086fe57b42Smillert void
100934ae4198Skrw editor_delete(struct disklabel *lp, char *p)
10106fe57b42Smillert {
101166df1f0cSkrw 	struct partition *pp;
1012135c90d1Skrw 	int partno;
10136fe57b42Smillert 
10146fe57b42Smillert 	if (p == NULL) {
1015c33fcabaSmillert 		p = getstring("partition to delete",
1016945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
1017945ae268Smillert 		    NULL);
10186fe57b42Smillert 	}
101996a888c6Smillert 	if (p == NULL) {
102096a888c6Smillert 		fputs("Command aborted\n", stderr);
102196a888c6Smillert 		return;
102296a888c6Smillert 	}
1023945ae268Smillert 	if (p[0] == '*') {
10249fdcb4d6Skrw 		zero_partitions(lp);
1025945ae268Smillert 		return;
1026945ae268Smillert 	}
1027135c90d1Skrw 	partno = p[0] - 'a';
1028135c90d1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10296c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10306c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
103133262abfSmiod 		return;
103266df1f0cSkrw 	}
1033135c90d1Skrw 	pp = &lp->d_partitions[partno];
103466df1f0cSkrw 
103566df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
103666df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
103733262abfSmiod 		return;
103866df1f0cSkrw 	}
103966df1f0cSkrw 
10406fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
1041135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
104234ae4198Skrw 	free(mountpoints[partno]);
104334ae4198Skrw 	mountpoints[partno] = NULL;
10446fe57b42Smillert }
10456fe57b42Smillert 
10466fe57b42Smillert /*
10476fe57b42Smillert  * Change the size of an existing partition.
10486fe57b42Smillert  */
10496fe57b42Smillert void
10509fdcb4d6Skrw editor_change(struct disklabel *lp, char *p)
10516fe57b42Smillert {
10524b9a3bdaSmillert 	struct partition *pp;
105366df1f0cSkrw 	int partno;
10546fe57b42Smillert 
10556fe57b42Smillert 	if (p == NULL) {
1056c33fcabaSmillert 		p = getstring("partition to change size",
10576fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
10586fe57b42Smillert 	}
105996a888c6Smillert 	if (p == NULL) {
106096a888c6Smillert 		fputs("Command aborted\n", stderr);
106196a888c6Smillert 		return;
106296a888c6Smillert 	}
10636fe57b42Smillert 	partno = p[0] - 'a';
10646c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
10656c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
10666c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
10676fe57b42Smillert 		return;
10686fe57b42Smillert 	}
10694b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
10706fe57b42Smillert 
107166df1f0cSkrw 	if (DL_GETPSIZE(pp) == 0) {
107266df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
107366df1f0cSkrw 		return;
107466df1f0cSkrw 	}
107566df1f0cSkrw 
107614192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
107714192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
107814192793Skrw 	    p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno));
10797da73705Skrw 
108059ccf790Skrw 	/* Get new size */
10819fdcb4d6Skrw 	get_size(lp, partno);
10826fe57b42Smillert }
10836fe57b42Smillert 
10846fe57b42Smillert /*
10856fe57b42Smillert  * Sort the partitions based on starting offset.
10866fe57b42Smillert  * This assumes there can be no overlap.
10876fe57b42Smillert  */
10886fe57b42Smillert int
10898809fabbSderaadt partition_cmp(const void *e1, const void *e2)
10906fe57b42Smillert {
10916fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10926fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10931e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
10941e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
10956fe57b42Smillert 
10961e0ad43cSotto 	if (o1 < o2)
1097651d5bd9Sotto 		return -1;
10981e0ad43cSotto 	else if (o1 > o2)
1099651d5bd9Sotto 		return 1;
1100651d5bd9Sotto 	else
1101651d5bd9Sotto 		return 0;
11026fe57b42Smillert }
11036fe57b42Smillert 
11046fe57b42Smillert char *
11058809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval)
11066fe57b42Smillert {
11076fe57b42Smillert 	static char buf[BUFSIZ];
11086fe57b42Smillert 	int n;
11096fe57b42Smillert 
11106fe57b42Smillert 	buf[0] = '\0';
11116fe57b42Smillert 	do {
11126fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
11136e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1114260513deSmillert 			buf[0] = '\0';
111596a888c6Smillert 			if (feof(stdin)) {
111624c6582eSmillert 				clearerr(stdin);
111796a888c6Smillert 				putchar('\n');
111896a888c6Smillert 				return(NULL);
111996a888c6Smillert 			}
11206e0becc5Smillert 		}
11216fe57b42Smillert 		n = strlen(buf);
11226fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11236fe57b42Smillert 			buf[--n] = '\0';
11246fe57b42Smillert 		if (buf[0] == '?')
11256fe57b42Smillert 			puts(helpstring);
11264fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
11274fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
11286fe57b42Smillert 	} while (buf[0] == '?');
11296fe57b42Smillert 
11306fe57b42Smillert 	return(&buf[0]);
11316fe57b42Smillert }
11326fe57b42Smillert 
11336fe57b42Smillert /*
11341e0ad43cSotto  * Returns ULLONG_MAX on error
113524a2c1a4Smillert  * Usually only called by helper functions.
11366fe57b42Smillert  */
11371e0ad43cSotto u_int64_t
1138dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring,
11391e0ad43cSotto     u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags)
11406fe57b42Smillert {
11416fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
11421e0ad43cSotto 	u_int64_t rval = oval;
1143e04edc8bSkrw 	int64_t mult = 1;
11446fe57b42Smillert 	size_t n;
114514cc915fSmillert 	double d, percent = 1.0;
11466fe57b42Smillert 
11474b9a3bdaSmillert 	/* We only care about the remainder */
11484b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
11494b9a3bdaSmillert 
11506fe57b42Smillert 	buf[0] = '\0';
11516fe57b42Smillert 	do {
11521e0ad43cSotto 		printf("%s: [%llu] ", prompt, oval);
11536e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11546e0becc5Smillert 			buf[0] = '\0';
115596a888c6Smillert 			if (feof(stdin)) {
115624c6582eSmillert 				clearerr(stdin);
115796a888c6Smillert 				putchar('\n');
11581e0ad43cSotto 				return(ULLONG_MAX - 1);
115996a888c6Smillert 			}
11606e0becc5Smillert 		}
11616fe57b42Smillert 		n = strlen(buf);
11626fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11636fe57b42Smillert 			buf[--n] = '\0';
11646fe57b42Smillert 		if (buf[0] == '?')
11656fe57b42Smillert 			puts(helpstring);
11666fe57b42Smillert 	} while (buf[0] == '?');
11676fe57b42Smillert 
11686fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11696fe57b42Smillert 		rval = maxval;
11706fe57b42Smillert 	} else {
11716fe57b42Smillert 		/* deal with units */
11726fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11736fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
117496a888c6Smillert 				switch (tolower(buf[n-1])) {
11756fe57b42Smillert 
11766fe57b42Smillert 				case 'c':
11776fe57b42Smillert 					mult = lp->d_secpercyl;
11786fe57b42Smillert 					buf[--n] = '\0';
11796fe57b42Smillert 					break;
11806fe57b42Smillert 				case 'b':
11816fe57b42Smillert 					mult = -lp->d_secsize;
11826fe57b42Smillert 					buf[--n] = '\0';
11836fe57b42Smillert 					break;
11846fe57b42Smillert 				case 'k':
118550c0f47aSkrw 					if (lp->d_secsize > 1024)
1186e04edc8bSkrw 						mult = -lp->d_secsize / 1024LL;
118750c0f47aSkrw 					else
1188e04edc8bSkrw 						mult = 1024LL / lp->d_secsize;
11896fe57b42Smillert 					buf[--n] = '\0';
11906fe57b42Smillert 					break;
11916fe57b42Smillert 				case 'm':
1192e04edc8bSkrw 					mult = (1024LL * 1024) / lp->d_secsize;
11936fe57b42Smillert 					buf[--n] = '\0';
11946fe57b42Smillert 					break;
11951a51a1eeSmillert 				case 'g':
1196e04edc8bSkrw 					mult = (1024LL * 1024 * 1024) /
1197e04edc8bSkrw 					    lp->d_secsize;
1198e04edc8bSkrw 					buf[--n] = '\0';
1199e04edc8bSkrw 					break;
1200e04edc8bSkrw 				case 't':
1201e04edc8bSkrw 					mult = (1024LL * 1024 * 1024 * 1024) /
1202e04edc8bSkrw 					    lp->d_secsize;
12031a51a1eeSmillert 					buf[--n] = '\0';
12041a51a1eeSmillert 					break;
120514cc915fSmillert 				case '%':
120614cc915fSmillert 					buf[--n] = '\0';
12074659aa0dSotto 					p = &buf[0];
12084659aa0dSotto 					if (*p == '+' || *p == '-')
12094659aa0dSotto 						operator = *p++;
12104659aa0dSotto 					percent = strtod(p, NULL) / 100.0;
12111e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
12121e0ad43cSotto 					    DL_GETDSIZE(lp));
121314cc915fSmillert 					break;
121414cc915fSmillert 				case '&':
121514cc915fSmillert 					buf[--n] = '\0';
12164659aa0dSotto 					p = &buf[0];
12174659aa0dSotto 					if (*p == '+' || *p == '-')
12184659aa0dSotto 						operator = *p++;
12194659aa0dSotto 					percent = strtod(p, NULL) / 100.0;
12201e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
122114cc915fSmillert 					    maxval);
122214cc915fSmillert 					break;
12236fe57b42Smillert 				}
122496a888c6Smillert 			}
12256fe57b42Smillert 
12266fe57b42Smillert 			/* Did they give us an operator? */
12276fe57b42Smillert 			p = &buf[0];
12286fe57b42Smillert 			if (*p == '+' || *p == '-')
12296fe57b42Smillert 				operator = *p++;
12306fe57b42Smillert 
12316fe57b42Smillert 			endptr = p;
123296a888c6Smillert 			errno = 0;
123396a888c6Smillert 			d = strtod(p, &endptr);
123496a888c6Smillert 			if (errno == ERANGE)
12351e0ad43cSotto 				rval = ULLONG_MAX;	/* too big/small */
123696a888c6Smillert 			else if (*endptr != '\0') {
12376fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
12381e0ad43cSotto 				rval = ULLONG_MAX;
12396fe57b42Smillert 			} else {
124096a888c6Smillert 				/* XXX - should check for overflow */
124196a888c6Smillert 				if (mult > 0)
124214cc915fSmillert 					rval = d * mult * percent;
124396a888c6Smillert 				else
124496a888c6Smillert 					/* Negative mult means divide (fancy) */
124514cc915fSmillert 					rval = d / (-mult) * percent;
12466fe57b42Smillert 
124796a888c6Smillert 				/* Apply the operator */
12486fe57b42Smillert 				if (operator == '+')
12496fe57b42Smillert 					rval += oval;
12506fe57b42Smillert 				else if (operator == '-')
12516fe57b42Smillert 					rval = oval - rval;
12526fe57b42Smillert 			}
12536fe57b42Smillert 		}
12546fe57b42Smillert 	}
12558390cf28Smillert 	if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) {
125696a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
12578390cf28Smillert 		if (
1258fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
1259fc1a4cc6Sderaadt 		    ((lp->d_flags & D_VENDOR) || mult != 1) &&
1260fc1a4cc6Sderaadt #else
12618390cf28Smillert 		    mult != 1 &&
1262dbffb156Smillert #endif
12638390cf28Smillert 		    (rval + offset) % lp->d_secpercyl != 0) {
12641e0ad43cSotto 			u_int64_t cyls;
1265dbffb156Smillert 
12668390cf28Smillert 			/* Round to higher cylinder but no more than maxval */
12678390cf28Smillert 			cyls = (rval / lp->d_secpercyl) + 1;
12688390cf28Smillert 			if ((cyls * lp->d_secpercyl) - offset > maxval)
1269dbffb156Smillert 				cyls--;
12704b9a3bdaSmillert 			rval = (cyls * lp->d_secpercyl) - offset;
12718390cf28Smillert 			printf("Rounding to cylinder: %llu\n", rval);
12726fe57b42Smillert 		}
12734b9a3bdaSmillert 	}
12746fe57b42Smillert 
12756fe57b42Smillert 	return(rval);
12766fe57b42Smillert }
12776fe57b42Smillert 
12786fe57b42Smillert /*
12791f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
12801f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
12816fe57b42Smillert  */
12826fe57b42Smillert int
12831f0f871dSkrw has_overlap(struct disklabel *lp)
12846fe57b42Smillert {
12856fe57b42Smillert 	struct partition **spp;
1286e6aa8bafSmillert 	int c, i, j;
1287e6aa8bafSmillert 	char buf[BUFSIZ];
12886fe57b42Smillert 
12890fbd3c97Skrw 	/* Get a sorted list of the in-use partitions. */
12900fbd3c97Skrw 	spp = sort_partitions(lp);
12916fe57b42Smillert 
12920fbd3c97Skrw 	/* If there are less than two partitions in use, there is no overlap. */
12930fbd3c97Skrw 	if (spp[1] == NULL)
12940fbd3c97Skrw 		return(0);
12956fe57b42Smillert 
12966fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12970fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
12980fbd3c97Skrw 		for (j = i + 1; spp[j] != NULL; j++) {
12996fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
13001e0ad43cSotto 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) {
13016fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
13026fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
13036fe57b42Smillert 				    / sizeof(**spp);
13046fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
13056fe57b42Smillert 				    / sizeof(**spp);
13066fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
13076fe57b42Smillert 				    'a' + i, 'a' + j);
1308366bf641Skrw 				printf("#    %16.16s %16.16s  fstype "
1309651d5bd9Sotto 				    "[fsize bsize  cpg]\n", "size", "offset");
131034ae4198Skrw 				display_partition(stdout, lp, i, 0);
131134ae4198Skrw 				display_partition(stdout, lp, j, 0);
13126fe57b42Smillert 
1313e6aa8bafSmillert 				/* Get partition to disable or ^D */
1314e6aa8bafSmillert 				do {
1315616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
13166fe57b42Smillert 					    'a' + i, 'a' + j);
1317e6aa8bafSmillert 					buf[0] = '\0';
1318616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1319616cd1c4Smillert 						putchar('\n');
1320e6aa8bafSmillert 						return(1);	/* ^D */
1321616cd1c4Smillert 					}
1322e6aa8bafSmillert 					c = buf[0] - 'a';
1323e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1324e6aa8bafSmillert 				    c != i && c != j);
1325e6aa8bafSmillert 
1326e6aa8bafSmillert 				/* Mark the selected one as unused */
13276fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
13281f0f871dSkrw 				return (has_overlap(lp));
13296fe57b42Smillert 			}
13306fe57b42Smillert 		}
13316fe57b42Smillert 	}
1332f0b4d0a9Smillert 
1333e6aa8bafSmillert 	return(0);
13346fe57b42Smillert }
13356fe57b42Smillert 
13366fe57b42Smillert void
13379fdcb4d6Skrw edit_parms(struct disklabel *lp)
13386fe57b42Smillert {
13396fe57b42Smillert 	char *p;
13409fdcb4d6Skrw 	u_int64_t freesectors, ui;
134196a888c6Smillert 	struct disklabel oldlabel = *lp;
13426fe57b42Smillert 
1343ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
13446fe57b42Smillert 
13450f820bbbSmillert 	/* disk type */
13460f820bbbSmillert 	for (;;) {
1347c33fcabaSmillert 		p = getstring("disk type",
134841282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
134941282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
135096a888c6Smillert 		if (p == NULL) {
135196a888c6Smillert 			fputs("Command aborted\n", stderr);
135296a888c6Smillert 			return;
135396a888c6Smillert 		}
135441282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
135541282a2aSmillert 			ui = DTYPE_ESDI;
135641282a2aSmillert 		else
135741282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
135841282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13590f820bbbSmillert 				;
13600f820bbbSmillert 		if (ui < DKMAXTYPES) {
13610f820bbbSmillert 			break;
13620f820bbbSmillert 		} else {
13630f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13640f820bbbSmillert 			fputs("Valid types are: ", stdout);
13650f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13660f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13670f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13680f820bbbSmillert 					fputs(", ", stdout);
13690f820bbbSmillert 			}
13700f820bbbSmillert 			putchar('\n');
13710f820bbbSmillert 		}
13720f820bbbSmillert 	}
13730f820bbbSmillert 	lp->d_type = ui;
13740f820bbbSmillert 
13756fe57b42Smillert 	/* pack/label id */
1376c33fcabaSmillert 	p = getstring("label name",
13776fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13786fe57b42Smillert 	    lp->d_packname);
137996a888c6Smillert 	if (p == NULL) {
138096a888c6Smillert 		fputs("Command aborted\n", stderr);
138196a888c6Smillert 		*lp = oldlabel;		/* undo damage */
138296a888c6Smillert 		return;
138396a888c6Smillert 	}
13844fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
13856fe57b42Smillert 
13866fe57b42Smillert 	/* sectors/track */
13876fe57b42Smillert 	for (;;) {
1388dea75673Skrw 		ui = getuint(lp, "sectors/track",
1389cfd24250Skrw 		    "The Number of sectors per track.", lp->d_nsectors,
13904b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
13911e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
139296a888c6Smillert 			fputs("Command aborted\n", stderr);
139396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
139496a888c6Smillert 			return;
13951e0ad43cSotto 		} if (ui == ULLONG_MAX)
13966fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13976fe57b42Smillert 		else
13986fe57b42Smillert 			break;
13996fe57b42Smillert 	}
14006fe57b42Smillert 	lp->d_nsectors = ui;
14016fe57b42Smillert 
14026fe57b42Smillert 	/* tracks/cylinder */
14036fe57b42Smillert 	for (;;) {
1404dea75673Skrw 		ui = getuint(lp, "tracks/cylinder",
14056fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
14064b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
14071e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
140896a888c6Smillert 			fputs("Command aborted\n", stderr);
140996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
141096a888c6Smillert 			return;
14111e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14126fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14136fe57b42Smillert 		else
14146fe57b42Smillert 			break;
14156fe57b42Smillert 	}
14166fe57b42Smillert 	lp->d_ntracks = ui;
14176fe57b42Smillert 
14186fe57b42Smillert 	/* sectors/cylinder */
1419148b6188Smillert 	for (;;) {
1420dea75673Skrw 		ui = getuint(lp, "sectors/cylinder",
1421148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
14224b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
14234b9a3bdaSmillert 		    0, 0);
14241e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
142596a888c6Smillert 			fputs("Command aborted\n", stderr);
142696a888c6Smillert 			*lp = oldlabel;		/* undo damage */
142796a888c6Smillert 			return;
14281e0ad43cSotto 		} else if (ui == ULLONG_MAX)
1429148b6188Smillert 			fputs("Invalid entry\n", stderr);
1430148b6188Smillert 		else
1431148b6188Smillert 			break;
1432148b6188Smillert 	}
1433148b6188Smillert 	lp->d_secpercyl = ui;
14346fe57b42Smillert 
14356fe57b42Smillert 	/* number of cylinders */
14366fe57b42Smillert 	for (;;) {
1437dea75673Skrw 		ui = getuint(lp, "number of cylinders",
14386fe57b42Smillert 		    "The total number of cylinders on the disk.",
14394b9a3bdaSmillert 		    lp->d_ncylinders, lp->d_ncylinders, 0, 0);
14401e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
144196a888c6Smillert 			fputs("Command aborted\n", stderr);
144296a888c6Smillert 			*lp = oldlabel;		/* undo damage */
144396a888c6Smillert 			return;
14441e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14456fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14466fe57b42Smillert 		else
14476fe57b42Smillert 			break;
14486fe57b42Smillert 	}
14496fe57b42Smillert 	lp->d_ncylinders = ui;
14506fe57b42Smillert 
14516fe57b42Smillert 	/* total sectors */
14526fe57b42Smillert 	for (;;) {
145334af67a3Sotto 		u_int64_t nsec = MAX(DL_GETDSIZE(lp),
145434af67a3Sotto 		    (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
1455dea75673Skrw 		ui = getuint(lp, "total sectors",
14566fe57b42Smillert 		    "The total number of sectors on the disk.",
1457baaa8969Smillert 		    nsec, nsec, 0, 0);
14581e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
145996a888c6Smillert 			fputs("Command aborted\n", stderr);
146096a888c6Smillert 			*lp = oldlabel;		/* undo damage */
146196a888c6Smillert 			return;
14621e0ad43cSotto 		} else if (ui == ULLONG_MAX)
14636fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14641e0ad43cSotto 		else if (ui > DL_GETDSIZE(lp) &&
14651e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
1466f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1467f98aebd4Smillert 			    "partition.");
14686fe57b42Smillert 			break;
14691e0ad43cSotto 		} else if (ui < DL_GETDSIZE(lp) &&
14701e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
14716fe57b42Smillert 			/* shrink free count */
14729fdcb4d6Skrw 			freesectors = editor_countfree(lp);
14739fdcb4d6Skrw 			if (DL_GETDSIZE(lp) - ui > freesectors)
14746fe57b42Smillert 				fprintf(stderr,
14751e0ad43cSotto 				    "Not enough free space to shrink by %llu "
14761e0ad43cSotto 				    "sectors (only %llu sectors left)\n",
14779fdcb4d6Skrw 				    DL_GETDSIZE(lp) - ui, freesectors);
1478c4f83f03Skrw 			else
14796fe57b42Smillert 				break;
14806fe57b42Smillert 		} else
14816fe57b42Smillert 			break;
14826fe57b42Smillert 	}
148341ed49b7Smillert 	/* Adjust ending_sector if necessary. */
148478f0fb17Skrw 	if (ending_sector > ui) {
148596a888c6Smillert 		ending_sector = ui;
148678f0fb17Skrw 		DL_SETBEND(lp, ending_sector);
148778f0fb17Skrw 	}
14881e0ad43cSotto 	DL_SETDSIZE(lp, ui);
14896fe57b42Smillert }
1490a7e61405Smillert 
1491a7e61405Smillert struct partition **
14920fbd3c97Skrw sort_partitions(struct disklabel *lp)
1493a7e61405Smillert {
1494d18c2a43Skrw 	static struct partition *spp[MAXPARTITIONS+2];
14950fbd3c97Skrw 	int i, npartitions;
1496a7e61405Smillert 
1497d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1498d18c2a43Skrw 
1499a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1500a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1501a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
15021e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1503a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1504a7e61405Smillert 	}
1505a7e61405Smillert 
1506a7e61405Smillert 	/*
1507a7e61405Smillert 	 * Sort the partitions based on starting offset.
1508a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1509a7e61405Smillert 	 */
1510a7e61405Smillert 	if (npartitions > 1)
1511a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1512a7e61405Smillert 		    partition_cmp))
1513a7e61405Smillert 			err(4, "failed to sort partition table");
1514a7e61405Smillert 
1515a7e61405Smillert 	return(spp);
1516a7e61405Smillert }
15170f820bbbSmillert 
15180f820bbbSmillert /*
15190f820bbbSmillert  * Get a valid disk type if necessary.
15200f820bbbSmillert  */
15210f820bbbSmillert void
15228809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev)
15230f820bbbSmillert {
15240f820bbbSmillert 	int i;
1525803ff7d5Smillert 	char *s, *def = "SCSI";
1526803ff7d5Smillert 	struct dtypes {
1527803ff7d5Smillert 		char *dev;
1528803ff7d5Smillert 		char *type;
1529803ff7d5Smillert 	} dtypes[] = {
1530c33fcabaSmillert 		{ "sd",   "SCSI" },
1531c33fcabaSmillert 		{ "rz",   "SCSI" },
1532c33fcabaSmillert 		{ "wd",   "IDE" },
1533c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1534c33fcabaSmillert 		{ "xd",   "SMD" },
1535c33fcabaSmillert 		{ "xy",   "SMD" },
1536c33fcabaSmillert 		{ "hd",   "HP-IB" },
1537*d7878011Sderaadt 		{ "ccd",  "CCD" },		/* deprecated */
1538c33fcabaSmillert 		{ "vnd",  "VND" },
1539c33fcabaSmillert 		{ "svnd", "VND" },
1540c33fcabaSmillert 		{ NULL,   NULL }
1541803ff7d5Smillert 	};
1542803ff7d5Smillert 
1543803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1544803ff7d5Smillert 		if (*s == 'r')
1545803ff7d5Smillert 			s++;
1546803ff7d5Smillert 		i = strcspn(s, "0123456789");
1547803ff7d5Smillert 		s[i] = '\0';
1548803ff7d5Smillert 		dev = s;
1549803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1550803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1551803ff7d5Smillert 				def = dtypes[i].type;
1552803ff7d5Smillert 				break;
1553803ff7d5Smillert 			}
1554803ff7d5Smillert 		}
1555803ff7d5Smillert 	}
15560f820bbbSmillert 
15570f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15580f820bbbSmillert 		puts(banner);
15590f820bbbSmillert 		puts("Possible values are:");
1560eb5dd924Sderaadt 		printf("\"IDE\", ");
15610f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15620f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15630f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15640f820bbbSmillert 				fputs(", ", stdout);
15650f820bbbSmillert 		}
15660f820bbbSmillert 		putchar('\n');
15670f820bbbSmillert 
15680f820bbbSmillert 		for (;;) {
1569c33fcabaSmillert 			s = getstring("Disk type",
1570803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1571*d7878011Sderaadt 			    "ESDI, ST506, or floppy.", def);
157296a888c6Smillert 			if (s == NULL)
157396a888c6Smillert 				continue;
15745b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15755b412421Smillert 				lp->d_type = DTYPE_ESDI;
15765b412421Smillert 				return;
15775b412421Smillert 			}
15780f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15790f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15800f820bbbSmillert 					lp->d_type = i;
15810f820bbbSmillert 					return;
15820f820bbbSmillert 				}
15830f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15840f820bbbSmillert 			fputs("Valid types are: ", stdout);
15850f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15860f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15870f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15880f820bbbSmillert 					fputs(", ", stdout);
15890f820bbbSmillert 			}
15900f820bbbSmillert 			putchar('\n');
15910f820bbbSmillert 		}
15920f820bbbSmillert 	}
15930f820bbbSmillert }
159496a888c6Smillert 
159596a888c6Smillert /*
159696a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
159796a888c6Smillert  * from the user.
159896a888c6Smillert  */
159996a888c6Smillert void
16009fdcb4d6Skrw set_bounds(struct disklabel *lp)
160196a888c6Smillert {
16021e0ad43cSotto 	u_int64_t ui, start_temp;
160396a888c6Smillert 
160496a888c6Smillert 	/* Starting sector */
160596a888c6Smillert 	do {
1606dea75673Skrw 		ui = getuint(lp, "Starting sector",
160796a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
16081e0ad43cSotto 		  starting_sector, DL_GETDSIZE(lp), 0, 0);
16091e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
161096a888c6Smillert 			fputs("Command aborted\n", stderr);
161196a888c6Smillert 			return;
161296a888c6Smillert 		}
16131e0ad43cSotto 	} while (ui >= DL_GETDSIZE(lp));
161496a888c6Smillert 	start_temp = ui;
161596a888c6Smillert 
16164793b14cSmillert 	/* Size */
161796a888c6Smillert 	do {
1618dea75673Skrw 		ui = getuint(lp, "Size ('*' for entire disk)",
1619f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1620f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
16211e0ad43cSotto 		  DL_GETDSIZE(lp) - start_temp, 0, 0);
16221e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
162396a888c6Smillert 			fputs("Command aborted\n", stderr);
162496a888c6Smillert 			return;
162596a888c6Smillert 		}
16261e0ad43cSotto 	} while (ui > DL_GETDSIZE(lp) - start_temp);
16274793b14cSmillert 	ending_sector = start_temp + ui;
162878f0fb17Skrw 	DL_SETBEND(lp, ending_sector);
162996a888c6Smillert 	starting_sector = start_temp;
163078f0fb17Skrw 	DL_SETBSTART(lp, starting_sector);
163196a888c6Smillert }
163296a888c6Smillert 
163396a888c6Smillert /*
16340d63cfbaSjsing  * Allow user to interactively change disklabel UID.
16350d63cfbaSjsing  */
16360d63cfbaSjsing void
163769a6ffbcSjsing set_duid(struct disklabel *lp)
16380d63cfbaSjsing {
16390d63cfbaSjsing 	char *s;
16400d63cfbaSjsing 	int i;
16410d63cfbaSjsing 
1642f6ad9e2dSjsing 	printf("The disklabel UID is currently: "
1643f6ad9e2dSjsing 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
1644f6ad9e2dSjsing             lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
1645f6ad9e2dSjsing             lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
16460d63cfbaSjsing 
16470d63cfbaSjsing 	do {
164869a6ffbcSjsing 		s = getstring("duid", "The disklabel UID, given as a 16 "
16490d63cfbaSjsing 		    "character hexadecimal string.", NULL);
1650ce98d1aeShalex 		if (s == NULL || strlen(s) == 0) {
16510d63cfbaSjsing 			fputs("Command aborted\n", stderr);
16520d63cfbaSjsing 			return;
16530d63cfbaSjsing 		}
165469a6ffbcSjsing 		i = duid_parse(lp, s);
16550d63cfbaSjsing 		if (i != 0)
16560d63cfbaSjsing 			fputs("Invalid UID entered.\n", stderr);
16570d63cfbaSjsing 	} while (i != 0);
16580d63cfbaSjsing }
16590d63cfbaSjsing 
16600d63cfbaSjsing /*
166196a888c6Smillert  * Return a list of the "chunks" of free space available
166296a888c6Smillert  */
166396a888c6Smillert struct diskchunk *
16648809fabbSderaadt free_chunks(struct disklabel *lp)
166596a888c6Smillert {
166696a888c6Smillert 	struct partition **spp;
166796a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
166899bd27d2Skrw 	u_int64_t start, stop;
166996a888c6Smillert 	int i, numchunks;
167096a888c6Smillert 
16710fbd3c97Skrw 	/* Sort the in-use partitions based on offset */
16720fbd3c97Skrw 	spp = sort_partitions(lp);
167396a888c6Smillert 
167496a888c6Smillert 	/* If there are no partitions, it's all free. */
16750fbd3c97Skrw 	if (spp[0] == NULL) {
16762d8451b0Smillert 		chunks[0].start = starting_sector;
167796a888c6Smillert 		chunks[0].stop = ending_sector;
167896a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
167996a888c6Smillert 		return(chunks);
168096a888c6Smillert 	}
168196a888c6Smillert 
168296a888c6Smillert 	/* Find chunks of free space */
168396a888c6Smillert 	numchunks = 0;
16840fbd3c97Skrw 	if (DL_GETPOFFSET(spp[0]) > starting_sector) {
16852d8451b0Smillert 		chunks[0].start = starting_sector;
16861e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
168796a888c6Smillert 		numchunks++;
168896a888c6Smillert 	}
16890fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
169099bd27d2Skrw 		start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1691aff3f969Sotto 		if (start < starting_sector)
1692aff3f969Sotto 			start = starting_sector;
1693aff3f969Sotto 		else if (start > ending_sector)
1694aff3f969Sotto 			start = ending_sector;
169599bd27d2Skrw 		if (spp[i + 1] != NULL)
169699bd27d2Skrw 			stop = DL_GETPOFFSET(spp[i+1]);
169799bd27d2Skrw 		else
169899bd27d2Skrw 			stop = ending_sector;
1699aff3f969Sotto 		if (stop < starting_sector)
1700aff3f969Sotto 			stop = starting_sector;
1701aff3f969Sotto 		else if (stop > ending_sector)
1702aff3f969Sotto 			stop = ending_sector;
170399bd27d2Skrw 		if (start < stop) {
170499bd27d2Skrw 			chunks[numchunks].start = start;
170599bd27d2Skrw 			chunks[numchunks].stop = stop;
170696a888c6Smillert 			numchunks++;
170796a888c6Smillert 		}
170896a888c6Smillert 	}
170996a888c6Smillert 
171096a888c6Smillert 	/* Terminate and return */
171196a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
171296a888c6Smillert 	return(chunks);
171396a888c6Smillert }
17144793b14cSmillert 
17154793b14cSmillert void
171687023ed9Skrw find_bounds(struct disklabel *lp)
17174793b14cSmillert {
17186534e983Sderaadt 	starting_sector = DL_GETBSTART(lp);
17196534e983Sderaadt 	ending_sector = DL_GETBEND(lp);
1720b2d4a455Smiod 
17216534e983Sderaadt 	if (ending_sector) {
172234ae4198Skrw 		if (verbose)
172334ae4198Skrw 			printf("Treating sectors %llu-%llu as the OpenBSD"
172434ae4198Skrw 			    " portion of the disk.\nYou can use the 'b'"
172534ae4198Skrw 			    " command to change this.\n\n", starting_sector,
172634ae4198Skrw 			    ending_sector);
1727b2d4a455Smiod 	} else {
1728b2d4a455Smiod #if (NUMBOOT == 1)
1729d3f02056Smillert 		/* Boot blocks take up the first cylinder */
1730d3f02056Smillert 		starting_sector = lp->d_secpercyl;
173134ae4198Skrw 		if (verbose)
173234ae4198Skrw 			printf("Reserving the first data cylinder for boot"
173334ae4198Skrw 			    " blocks.\nYou can use the 'b' command to change"
173434ae4198Skrw 			    " this.\n\n");
17354793b14cSmillert #endif
17364793b14cSmillert 	}
1737b2d4a455Smiod }
1738c0bdc608Smillert 
1739c0bdc608Smillert /*
1740c0bdc608Smillert  * Calculate free space.
1741c0bdc608Smillert  */
17429fdcb4d6Skrw u_int64_t
17439fdcb4d6Skrw editor_countfree(struct disklabel *lp)
1744c0bdc608Smillert {
1745d93cb2bbSkrw 	struct diskchunk *chunks;
17469fdcb4d6Skrw 	u_int64_t freesectors = 0;
1747c0bdc608Smillert 	int i;
1748c0bdc608Smillert 
1749d93cb2bbSkrw 	chunks = free_chunks(lp);
1750509930fbSotto 
1751d93cb2bbSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++)
17529fdcb4d6Skrw 		freesectors += chunks[i].stop - chunks[i].start;
17539fdcb4d6Skrw 
17549fdcb4d6Skrw 	return (freesectors);
1755c0bdc608Smillert }
1756617e6e4aSmillert 
1757617e6e4aSmillert void
17584d812bb6Slum editor_help(void)
1759617e6e4aSmillert {
1760617e6e4aSmillert 	puts("Available commands:");
1761617e6e4aSmillert 	puts(
17624d812bb6Slum " ? | h    - show help                 n [part] - set mount point\n"
176349159a67Skrw " A        - auto partition all space  p [unit] - print partitions\n"
176449159a67Skrw " a [part] - add partition             q        - quit & save changes\n"
17654659aa0dSotto " b        - set OpenBSD boundaries    R [part] - resize auto allocated partition\n"
176649159a67Skrw " c [part] - change partition size     r        - display free space\n"
17676aaa4aabSotto " D        - reset label to default    s [path] - save label to file\n"
17686aaa4aabSotto " d [part] - delete partition          U        - undo all changes\n"
17696aaa4aabSotto " e        - edit drive parameters     u        - undo last change\n"
17706aaa4aabSotto " g [d|u]  - [d]isk or [u]ser geometry w        - write label to disk\n"
17710d63cfbaSjsing " i        - modify disklabel UID      X        - toggle expert mode\n"
17720d63cfbaSjsing " l [unit] - print disk label header   x        - exit & lose changes\n"
17730d63cfbaSjsing " M        - disklabel(8) man page     z        - delete all partitions\n"
17740d63cfbaSjsing " m [part] - modify partition\n"
1775c4884206Skrw "\n"
1776c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1777e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n"
1778e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1779c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
17804d812bb6Slum 
1781617e6e4aSmillert }
1782bd6726faSmillert 
17834f3bbbf0Skrw void
17848809fabbSderaadt mpcopy(char **to, char **from)
1785bd6726faSmillert {
1786bd6726faSmillert 	int i;
17870612d09dSderaadt 	char *top;
1788bd6726faSmillert 
1789bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1790bd6726faSmillert 		if (from[i] != NULL) {
1791dcab0d16Sderaadt 			int len = strlen(from[i]) + 1;
1792dcab0d16Sderaadt 
17930612d09dSderaadt 			top = realloc(to[i], len);
17940612d09dSderaadt 			if (top == NULL)
1795bd6726faSmillert 				errx(4, "out of memory");
17960612d09dSderaadt 			to[i] = top;
1797dcab0d16Sderaadt 			(void)strlcpy(to[i], from[i], len);
1798bd6726faSmillert 		} else if (to[i] != NULL) {
1799bd6726faSmillert 			free(to[i]);
1800bd6726faSmillert 			to[i] = NULL;
1801bd6726faSmillert 		}
1802bd6726faSmillert 	}
1803bd6726faSmillert }
1804bd6726faSmillert 
1805bd6726faSmillert int
18068809fabbSderaadt mpequal(char **mp1, char **mp2)
1807bd6726faSmillert {
1808bd6726faSmillert 	int i;
1809bd6726faSmillert 
1810bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1811bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1812bd6726faSmillert 			continue;
1813bd6726faSmillert 
1814bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1815bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1816bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1817bd6726faSmillert 			return(0);
1818bd6726faSmillert 	}
1819bd6726faSmillert 	return(1);
1820bd6726faSmillert }
1821bd6726faSmillert 
182293160b9bSkrw void
182334ae4198Skrw mpsave(struct disklabel *lp)
1824bd6726faSmillert {
1825d8b446ceSderaadt 	int i, j;
1826bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
18273f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1828bd6726faSmillert 	FILE *fp;
1829fe01da94Skrw 	u_int8_t fstype;
1830bd6726faSmillert 
183193160b9bSkrw 	if (!fstabfile)
183293160b9bSkrw 		return;
183393160b9bSkrw 
18343f843443Smillert 	memset(&mi, 0, sizeof(mi));
18353f843443Smillert 
1836d8b446ceSderaadt 	for (i = 0; i < MAXPARTITIONS; i++) {
1837fe01da94Skrw 		fstype = lp->d_partitions[i].p_fstype;
1838fe01da94Skrw 		if (mountpoints[i] != NULL || fstype == FS_SWAP) {
183934ae4198Skrw 			mi[i].mountpoint = mountpoints[i];
18403f843443Smillert 			mi[i].partno = i;
1841bd6726faSmillert 		}
1842bd6726faSmillert 	}
1843bd6726faSmillert 
184434ae4198Skrw 	/* Convert specname to bdev */
1845d6d80bb0Skrw 	if (uidflag) {
1846d6d80bb0Skrw 		snprintf(bdev, sizeof(bdev),
1847d6d80bb0Skrw 		    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
1848d6d80bb0Skrw 		    lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3],
1849d6d80bb0Skrw 		    lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7],
1850d6d80bb0Skrw 		    specname[strlen(specname)-1]);
1851d6d80bb0Skrw 	} else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
185234ae4198Skrw 	    specname[sizeof(_PATH_DEV) - 1] == 'r') {
1853bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
185434ae4198Skrw 		    &specname[sizeof(_PATH_DEV)]);
1855bd6726faSmillert 	} else {
185634ae4198Skrw 		if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
185793160b9bSkrw 			return;
1858bd6726faSmillert 		*p = '\0';
185934ae4198Skrw 		snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1860bd6726faSmillert 		*p = 'r';
1861bd6726faSmillert 	}
1862bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1863bd6726faSmillert 
18643f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
18653f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
18663f843443Smillert 
1867d71533c9Stedu 	if ((fp = fopen(fstabfile, "w"))) {
1868fe01da94Skrw 		for (i = 0; i < MAXPARTITIONS; i++) {
18695fea0b85Smillert 			j =  mi[i].partno;
1870fe01da94Skrw 			fstype = lp->d_partitions[j].p_fstype;
1871fe01da94Skrw 			if (fstype == FS_SWAP) {
1872fe01da94Skrw 				fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j);
1873fe01da94Skrw 			} else if (mi[i].mountpoint) {
1874fe01da94Skrw 				fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev,
1875fe01da94Skrw 				    'a' + j, mi[i].mountpoint,
1876fe01da94Skrw 				    fstypesnames[fstype], j == 0 ? 1 : 2);
1877fe01da94Skrw 			}
1878bd6726faSmillert 		}
1879bd6726faSmillert 		fclose(fp);
188093160b9bSkrw 	}
1881bd6726faSmillert }
188224a2c1a4Smillert 
188324a2c1a4Smillert int
1884604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
188524a2c1a4Smillert {
1886604d3bdeSkrw 	struct diskchunk *chunks;
188724a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
188815c15d8aSkrw 	u_int64_t ui, maxsize;
1889604d3bdeSkrw 	int i, fstype;
189024a2c1a4Smillert 
1891dea75673Skrw 	ui = getuint(lp, "offset",
18921e0ad43cSotto 	   "Starting sector for this partition.",
18931e0ad43cSotto 	   DL_GETPOFFSET(pp),
18941e0ad43cSotto 	   DL_GETPOFFSET(pp), 0, DO_CONVERSIONS |
189524a2c1a4Smillert 	   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
1896e9ff19beSkrw 
1897e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
189824a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1899e9ff19beSkrw 	else if (ui == ULLONG_MAX)
190024a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
190140e98e9fSkrw 	else if (ui < starting_sector || ui >= ending_sector)
1902e9ff19beSkrw 		fprintf(stderr, "The offset must be >= %llu and < %llu, "
1903e9ff19beSkrw 		    "the limits of the OpenBSD portion\n"
1904e9ff19beSkrw 		    "of the disk. The 'b' command can change these limits.\n",
190540e98e9fSkrw 		    starting_sector, ending_sector);
1906fc1a4cc6Sderaadt #ifdef SUN_AAT0
190749bf537cSderaadt 	else if (partno == 0 && ui != 0)
190849bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
190940f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
191049bf537cSderaadt #endif
191115c15d8aSkrw 	else {
1912604d3bdeSkrw 		fstype = pp->p_fstype;
1913604d3bdeSkrw 		pp->p_fstype = FS_UNUSED;
1914604d3bdeSkrw 		chunks = free_chunks(lp);
1915604d3bdeSkrw 		pp->p_fstype = fstype;
1916e9ff19beSkrw 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
1917e9ff19beSkrw 			if (ui < chunks[i].start || ui >= chunks[i].stop)
191815c15d8aSkrw 				continue;
19191e0ad43cSotto 			DL_SETPOFFSET(pp, ui);
192015c15d8aSkrw 			maxsize = chunks[i].stop - DL_GETPOFFSET(pp);
192115c15d8aSkrw 			if (DL_GETPSIZE(pp) > maxsize)
192215c15d8aSkrw 				DL_SETPSIZE(pp, maxsize);
192324a2c1a4Smillert 			return (0);
192424a2c1a4Smillert 		}
192515c15d8aSkrw 		fputs("The offset must be in a free area.\n", stderr);
192615c15d8aSkrw 	}
1927e9ff19beSkrw 
1928e9ff19beSkrw 	/* Partition offset was not set. */
1929e9ff19beSkrw 	return (1);
193015c15d8aSkrw }
193124a2c1a4Smillert 
193224a2c1a4Smillert int
19339fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
193424a2c1a4Smillert {
193524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
193614192793Skrw 	u_int64_t maxsize, ui;
193714192793Skrw 
193814192793Skrw 	maxsize = max_partition_size(lp, partno);
193924a2c1a4Smillert 
1940dea75673Skrw 	ui = getuint(lp, "size", "Size of the partition. "
19417da73705Skrw 	    "You may also say +/- amount for a relative change.",
194214192793Skrw 	    DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp),
1943525051f1Sotto 	    DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS ||
1944525051f1Sotto 	    pp->p_fstype == FS_SWAP) ?  DO_ROUNDING : 0));
1945e9ff19beSkrw 
1946e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
194724a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1948e9ff19beSkrw 	else if (ui == ULLONG_MAX)
194924a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
195028e3704eSkrw 	else if (ui == 0)
195128e3704eSkrw 		fputs("The size must be > 0\n", stderr);
195240e98e9fSkrw 	else if (ui + DL_GETPOFFSET(pp) > ending_sector)
195340e98e9fSkrw 		fprintf(stderr, "The size can't be more than "
195440e98e9fSkrw 		    "%llu sectors, or the partition would\n"
195540e98e9fSkrw 		    "extend beyond the last sector (%llu) of the "
195640e98e9fSkrw 		    "OpenBSD portion of\nthe disk. "
195740e98e9fSkrw 		    "The 'b' command can change this limit.\n",
195840e98e9fSkrw 		    ending_sector - DL_GETPOFFSET(pp), ending_sector);
195914192793Skrw 	else if (ui > maxsize)
196014192793Skrw 		fprintf(stderr,"Sorry, there are only %llu sectors left\n",
196114192793Skrw 		    maxsize);
196259ccf790Skrw 	else {
196359ccf790Skrw 		DL_SETPSIZE(pp, ui);
196424a2c1a4Smillert 		return (0);
196524a2c1a4Smillert 	}
1966e9ff19beSkrw 
1967e9ff19beSkrw 	/* Partition size was not set. */
1968e9ff19beSkrw 	return (1);
1969e9ff19beSkrw }
197024a2c1a4Smillert 
197124a2c1a4Smillert int
19728809fabbSderaadt get_fsize(struct disklabel *lp, int partno)
197324a2c1a4Smillert {
19741e0ad43cSotto 	u_int64_t ui, fsize, frag;
197524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
197624a2c1a4Smillert 
1977a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
1978a4c87e64Skrw 		return (0);
1979a4c87e64Skrw 
1980ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1981ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1982ddfcbf38Sotto 	if (fsize == 0)
1983ddfcbf38Sotto 		frag = 8;
1984ddfcbf38Sotto 
198524a2c1a4Smillert 	for (;;) {
1986dea75673Skrw 		ui = getuint(lp, "fragment size",
19873c92d7f2Stedu 		    "Size of fs block fragments.  Usually 2048 or 512.",
1988ddfcbf38Sotto 		    fsize, fsize, 0, 0);
19891e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
199024a2c1a4Smillert 			fputs("Command aborted\n", stderr);
199124a2c1a4Smillert 			return(1);
19921e0ad43cSotto 		} else if (ui == ULLONG_MAX)
199324a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
199424a2c1a4Smillert 		else
199524a2c1a4Smillert 			break;
199624a2c1a4Smillert 	}
199724a2c1a4Smillert 	if (ui == 0)
199824a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
1999ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag);
200024a2c1a4Smillert 	return(0);
200124a2c1a4Smillert }
200224a2c1a4Smillert 
200324a2c1a4Smillert int
20048809fabbSderaadt get_bsize(struct disklabel *lp, int partno)
200524a2c1a4Smillert {
2006a49bdda8Skrw 	u_int64_t adj, ui, bsize, frag, fsize;
200724a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
200824a2c1a4Smillert 
2009a49bdda8Skrw 	if (pp->p_fstype != FS_BSDFFS)
2010a4c87e64Skrw 		return (0);
2011a4c87e64Skrw 
201224a2c1a4Smillert 	/* Avoid dividing by zero... */
2013ddfcbf38Sotto 	if (pp->p_fragblock == 0)
201424a2c1a4Smillert 		return(1);
2015ddfcbf38Sotto 
2016a49bdda8Skrw 	if (!expert)
2017a49bdda8Skrw 		goto align;
2018a49bdda8Skrw 
2019ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
2020ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
202124a2c1a4Smillert 
202224a2c1a4Smillert 	for (;;) {
2023dea75673Skrw 		ui = getuint(lp, "block size",
20243c92d7f2Stedu 		    "Size of filesystem blocks.  Usually 16384 or 4096.",
2025ddfcbf38Sotto 		    fsize * frag, fsize * frag,
202624a2c1a4Smillert 		    0, 0);
202724a2c1a4Smillert 
202824a2c1a4Smillert 		/* sanity checks */
20291e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
203024a2c1a4Smillert 			fputs("Command aborted\n", stderr);
203124a2c1a4Smillert 			return(1);
20321e0ad43cSotto 		} else if (ui == ULLONG_MAX)
203324a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
203424a2c1a4Smillert 		else if (ui < getpagesize())
203524a2c1a4Smillert 			fprintf(stderr,
203624a2c1a4Smillert 			    "Error: block size must be at least as big "
203724a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
2038ddfcbf38Sotto 		else if (ui % fsize != 0)
203924a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
204024a2c1a4Smillert 			    "fragment size.\n", stderr);
2041ddfcbf38Sotto 		else if (ui / fsize < 1)
204224a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
204324a2c1a4Smillert 			    "fragment size.\n", stderr);
204424a2c1a4Smillert 		else
204524a2c1a4Smillert 			break;
204624a2c1a4Smillert 	}
2047ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag);
2048a49bdda8Skrw 
2049a49bdda8Skrw align:
2050a49bdda8Skrw #ifndef SUN_CYLCHECK
2051a49bdda8Skrw 	bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) *
2052a49bdda8Skrw 	    DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize;
2053a49bdda8Skrw 	if (DL_GETPOFFSET(pp) != starting_sector) {
2054a49bdda8Skrw 		/* Can't change offset of first partition. */
2055a49bdda8Skrw 		adj = bsize - (DL_GETPOFFSET(pp) % bsize);
2056a49bdda8Skrw 		if (adj != 0 && adj != bsize) {
2057a49bdda8Skrw 			DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj);
2058a49bdda8Skrw 			DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj);
2059a49bdda8Skrw 		}
2060a49bdda8Skrw 	}
2061a49bdda8Skrw 	/* Always align end. */
2062a49bdda8Skrw 	adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize;
2063a49bdda8Skrw 	if (adj > 0)
2064a49bdda8Skrw 		DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj);
2065a49bdda8Skrw #endif
206624a2c1a4Smillert 	return(0);
206724a2c1a4Smillert }
206824a2c1a4Smillert 
206924a2c1a4Smillert int
20708809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
207124a2c1a4Smillert {
207224a2c1a4Smillert 	char *p;
20731e0ad43cSotto 	u_int64_t ui;
207424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
207524a2c1a4Smillert 
207624a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
2077c33fcabaSmillert 		p = getstring("FS type",
207824a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
207924a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
208024a2c1a4Smillert 		if (p == NULL) {
208124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
208224a2c1a4Smillert 			return(1);
208324a2c1a4Smillert 		}
208424a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
208524a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
208624a2c1a4Smillert 				pp->p_fstype = ui;
208724a2c1a4Smillert 				break;
208824a2c1a4Smillert 			}
208924a2c1a4Smillert 		}
209024a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
209124a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
209224a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
209324a2c1a4Smillert 		}
209424a2c1a4Smillert 	} else {
209524a2c1a4Smillert 		for (;;) {
2096dea75673Skrw 			ui = getuint(lp, "FS type (decimal)",
209724a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
209824a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
20991e0ad43cSotto 			if (ui == ULLONG_MAX - 1) {
210024a2c1a4Smillert 				fputs("Command aborted\n", stderr);
210124a2c1a4Smillert 				return(1);
21021e0ad43cSotto 			} if (ui == ULLONG_MAX)
210324a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
210424a2c1a4Smillert 			else
210524a2c1a4Smillert 				break;
210624a2c1a4Smillert 		}
210724a2c1a4Smillert 		pp->p_fstype = ui;
210824a2c1a4Smillert 	}
210924a2c1a4Smillert 	return(0);
211024a2c1a4Smillert }
211124a2c1a4Smillert 
211224a2c1a4Smillert int
211334ae4198Skrw get_mp(struct disklabel *lp, int partno)
211424a2c1a4Smillert {
211524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
2116ec9fde5fSkrw 	char *p;
2117ec9fde5fSkrw 	int i;
211824a2c1a4Smillert 
211934ae4198Skrw 	if (fstabfile && pp->p_fstype != FS_UNUSED &&
212024a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
212124a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
2122ddaff619Smillert 		for (;;) {
2123c33fcabaSmillert 			p = getstring("mount point",
212424a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
212534ae4198Skrw 			    mountpoints[partno] ? mountpoints[partno] : "none");
212624a2c1a4Smillert 			if (p == NULL) {
212724a2c1a4Smillert 				fputs("Command aborted\n", stderr);
212824a2c1a4Smillert 				return(1);
212924a2c1a4Smillert 			}
2130ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
213134ae4198Skrw 				free(mountpoints[partno]);
213234ae4198Skrw 				mountpoints[partno] = NULL;
2133ddaff619Smillert 				break;
2134ddaff619Smillert 			}
2135ec9fde5fSkrw 			for (i = 0; i < MAXPARTITIONS; i++)
213693160b9bSkrw 				if (mountpoints[i] != NULL && i != partno &&
2137ec9fde5fSkrw 				    strcmp(p, mountpoints[i]) == 0)
2138ec9fde5fSkrw 					break;
2139ec9fde5fSkrw 			if (i < MAXPARTITIONS) {
214093160b9bSkrw 				fprintf(stderr, "'%c' already being mounted at "
214193160b9bSkrw 				    "'%s'\n", 'a'+i, p);
2142ec9fde5fSkrw 				break;
2143ec9fde5fSkrw 			}
2144ddaff619Smillert 			if (*p == '/') {
2145ddaff619Smillert 				/* XXX - might as well realloc */
214634ae4198Skrw 				free(mountpoints[partno]);
214734ae4198Skrw 				if ((mountpoints[partno] = strdup(p)) == NULL)
214824a2c1a4Smillert 					errx(4, "out of memory");
2149ddaff619Smillert 				break;
2150ddaff619Smillert 			}
2151ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
215224a2c1a4Smillert 		}
215324a2c1a4Smillert 	}
215424a2c1a4Smillert 	return(0);
215524a2c1a4Smillert }
21563f843443Smillert 
21573f843443Smillert int
21588809fabbSderaadt micmp(const void *a1, const void *a2)
21593f843443Smillert {
21603f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
21613f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
21623f843443Smillert 
21633f843443Smillert 	/* We want all the NULLs at the end... */
21643f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
21653f843443Smillert 		return(0);
21663f843443Smillert 	else if (mi1->mountpoint == NULL)
21673f843443Smillert 		return(1);
21683f843443Smillert 	else if (mi2->mountpoint == NULL)
21693f843443Smillert 		return(-1);
21703f843443Smillert 	else
21713f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
21723f843443Smillert }
2173c33fcabaSmillert 
2174c33fcabaSmillert void
217587023ed9Skrw get_geometry(int f, struct disklabel **dgpp)
2176c33fcabaSmillert {
2177c33fcabaSmillert 	struct stat st;
2178c33fcabaSmillert 	struct disklabel *disk_geop;
217987023ed9Skrw 
2180c33fcabaSmillert 	if (fstat(f, &st) == -1)
2181c33fcabaSmillert 		err(4, "Can't stat device");
2182c33fcabaSmillert 
2183c33fcabaSmillert 	/* Get disk geometry */
2184c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2185c33fcabaSmillert 		errx(4, "out of memory");
21869a379a6cSkrw 	if (ioctl(f, DIOCGPDINFO, disk_geop) < 0)
21879a379a6cSkrw 		err(4, "ioctl DIOCGPDINFO");
2188c33fcabaSmillert 	*dgpp = disk_geop;
2189c33fcabaSmillert }
2190c33fcabaSmillert 
2191c33fcabaSmillert void
21928809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp,
219387023ed9Skrw     struct disklabel *ugp, char *p)
2194c33fcabaSmillert {
2195c33fcabaSmillert 	if (p == NULL) {
21969a36aa41Ssthen 		p = getstring("[d]isk or [u]ser geometry",
2197c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
21989a36aa41Ssthen 		    "itself thinks it is, or 'u' to use the geometry that "
21999a36aa41Ssthen 		    "was found in the label.",
2200c33fcabaSmillert 		    "d");
2201c33fcabaSmillert 	}
2202c33fcabaSmillert 	if (p == NULL) {
2203c33fcabaSmillert 		fputs("Command aborted\n", stderr);
2204c33fcabaSmillert 		return;
2205c33fcabaSmillert 	}
2206c33fcabaSmillert 	switch (*p) {
2207c33fcabaSmillert 	case 'd':
2208c33fcabaSmillert 	case 'D':
2209c33fcabaSmillert 		if (dgp == NULL)
2210c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2211c33fcabaSmillert 		else {
2212c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
2213c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
2214c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
2215c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
2216c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
221734af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(dgp));
2218c33fcabaSmillert 		}
2219c33fcabaSmillert 		break;
2220c33fcabaSmillert 	case 'u':
2221c33fcabaSmillert 	case 'U':
2222c33fcabaSmillert 		if (ugp == NULL)
2223c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2224c33fcabaSmillert 		else {
2225c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2226c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2227c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2228c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2229c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
223034af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(ugp));
2231c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2232c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2233c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2234c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2235c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
223634af67a3Sotto 			    DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp))
2237c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2238c33fcabaSmillert 				    "geometry.\n", stderr);
2239c33fcabaSmillert 		}
2240c33fcabaSmillert 		break;
2241c33fcabaSmillert 	default:
22429a36aa41Ssthen 		fputs("You must enter either 'd' or 'u'.\n", stderr);
2243c33fcabaSmillert 		break;
2244c33fcabaSmillert 	}
2245c33fcabaSmillert }
22469afbe9eeSmillert 
22479afbe9eeSmillert void
22489fdcb4d6Skrw zero_partitions(struct disklabel *lp)
22499afbe9eeSmillert {
22509afbe9eeSmillert 	int i;
22519afbe9eeSmillert 
2252b4ed6301Skrw 	for (i = 0; i < MAXPARTITIONS; i++) {
22539afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
2254b4ed6301Skrw 		free(mountpoints[i]);
2255b4ed6301Skrw 		mountpoints[i] = NULL;
2256b4ed6301Skrw 	}
2257b4ed6301Skrw 
225834af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
22599afbe9eeSmillert }
226014192793Skrw 
226114192793Skrw u_int64_t
226214192793Skrw max_partition_size(struct disklabel *lp, int partno)
226314192793Skrw {
226414192793Skrw 	struct partition *pp = &lp->d_partitions[partno];
226514192793Skrw 	struct diskchunk *chunks;
226644ffe03bSotto 	u_int64_t maxsize = 0, offset;
226714192793Skrw 	int fstype, i;
226814192793Skrw 
226914192793Skrw 	fstype = pp->p_fstype;
227014192793Skrw 	pp->p_fstype = FS_UNUSED;
227114192793Skrw 	chunks = free_chunks(lp);
227214192793Skrw 	pp->p_fstype = fstype;
227314192793Skrw 
227414192793Skrw 	offset = DL_GETPOFFSET(pp);
227514192793Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
227614192793Skrw 		if (offset < chunks[i].start || offset >= chunks[i].stop)
227714192793Skrw 			continue;
227814192793Skrw 		maxsize = chunks[i].stop - offset;
227914192793Skrw 		break;
228014192793Skrw 	}
228114192793Skrw 	return (maxsize);
228214192793Skrw }
2283aff3f969Sotto 
2284aff3f969Sotto void
2285aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp)
2286aff3f969Sotto {
2287aff3f969Sotto 	double d = scale(sz, unit, lp);
2288aff3f969Sotto 	if (d < 0)
2289aff3f969Sotto 		printf("%llu", sz);
2290aff3f969Sotto 	else
2291aff3f969Sotto 		printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
2292aff3f969Sotto }
2293aff3f969Sotto 
2294aff3f969Sotto void
229534ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr)
2296aff3f969Sotto {
2297aff3f969Sotto 	int i;
2298aff3f969Sotto 
2299352d199bSkrw 	unit = canonical_unit(lp, unit);
2300aff3f969Sotto 
2301aff3f969Sotto 	printf("OpenBSD area: ");
230259882f1dSkrw 	psize(starting_sector, 0, lp);
2303aff3f969Sotto 	printf("-");
230459882f1dSkrw 	psize(ending_sector, 0, lp);
2305aff3f969Sotto 	printf("; size: ");
2306aff3f969Sotto 	psize(ending_sector - starting_sector, unit, lp);
2307aff3f969Sotto 	printf("; free: ");
2308aff3f969Sotto 	psize(fr, unit, lp);
2309aff3f969Sotto 
2310aff3f969Sotto 	printf("\n#    %16.16s %16.16s  fstype [fsize bsize  cpg]\n",
2311aff3f969Sotto 	    "size", "offset");
2312aff3f969Sotto 	for (i = 0; i < lp->d_npartitions; i++)
231334ae4198Skrw 		display_partition(stdout, lp, i, unit);
2314aff3f969Sotto }
2315aff3f969Sotto 
2316