xref: /openbsd/sbin/disklabel/editor.c (revision 854d339c)
1*854d339cSjan /*	$OpenBSD: editor.c,v 1.418 2024/03/22 21:49:52 jan Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
4bf198cc6Smillert  * Copyright (c) 1997-2000 Todd C. Miller <millert@openbsd.org>
56fe57b42Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert  */
186fe57b42Smillert 
1978eb0b7eSderaadt #include <sys/param.h>	/* MAXBSIZE DEV_BSIZE */
206fe57b42Smillert #include <sys/types.h>
21b9fc9a72Sderaadt #include <sys/signal.h>
22c33fcabaSmillert #include <sys/stat.h>
23c33fcabaSmillert #include <sys/ioctl.h>
2491f4f7d8Sdlg #include <sys/dkio.h>
258dde8bb6Sotto #include <sys/sysctl.h>
266fe57b42Smillert #define	DKTYPENAMES
276fe57b42Smillert #include <sys/disklabel.h>
286fe57b42Smillert 
296fe57b42Smillert #include <ufs/ffs/fs.h>
306fe57b42Smillert 
316fe57b42Smillert #include <ctype.h>
326fe57b42Smillert #include <err.h>
336fe57b42Smillert #include <errno.h>
346fe57b42Smillert #include <string.h>
35803ff7d5Smillert #include <libgen.h>
36f1bc1b27Skrw #include <stdint.h>
376fe57b42Smillert #include <stdio.h>
386fe57b42Smillert #include <stdlib.h>
396fe57b42Smillert #include <unistd.h>
40b9fc9a72Sderaadt #include <limits.h>
416fe57b42Smillert 
42f21a098bSotto #include "extern.h"
434793b14cSmillert #include "pathnames.h"
444793b14cSmillert 
45f409a94aSkrw #define	ROUNDUP(_s, _a)		((((_s) + (_a) - 1) / (_a)) * (_a))
46f409a94aSkrw #define	ROUNDDOWN(_s, _a)	(((_s) / (_a)) * (_a))
47b46f7512Skrw #define	CHUNKSZ(_c)		((_c)->stop - (_c)->start)
48b9fc9a72Sderaadt 
49117239d3Skrw /* flags for getuint64() */
506fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
516fe57b42Smillert #define	DO_ROUNDING	0x00000002
526fe57b42Smillert 
5340b226e8Skrw /* flags for alignpartition() */
5440b226e8Skrw #define	ROUND_OFFSET_UP		0x00000001
5540b226e8Skrw #define	ROUND_OFFSET_DOWN	0x00000002
5640b226e8Skrw #define	ROUND_SIZE_UP		0x00000004
5740b226e8Skrw #define	ROUND_SIZE_DOWN		0x00000008
58922b28b8Skrw #define	ROUND_SIZE_OVERLAP	0x00000010
5940b226e8Skrw 
600db7769aSkrw /* Special return values for getnumber and getuint64() */
61aa3970cdSkrw #define	CMD_ABORTED	(ULLONG_MAX - 1)
62aa3970cdSkrw #define	CMD_BADVALUE	(ULLONG_MAX)
63aa3970cdSkrw 
6496a888c6Smillert /* structure to describe a portion of a disk */
6596a888c6Smillert struct diskchunk {
661e0ad43cSotto 	u_int64_t start;
671e0ad43cSotto 	u_int64_t stop;
6896a888c6Smillert };
6996a888c6Smillert 
703f843443Smillert /* used when sorting mountpoints in mpsave() */
713f843443Smillert struct mountinfo {
723f843443Smillert 	char *mountpoint;
733f843443Smillert 	int partno;
743f843443Smillert };
753f843443Smillert 
76557f712bSkrw /* used when allocating all space according to recommendations */
77557f712bSkrw 
78557f712bSkrw struct space_allocation {
79eafadddfSkrw 	u_int64_t	minsz;	/* starts as blocks, xlated to sectors. */
80eafadddfSkrw 	u_int64_t	maxsz;	/* starts as blocks, xlated to sectors. */
81557f712bSkrw 	int		rate;	/* % of extra space to use */
82557f712bSkrw 	char	       *mp;
83557f712bSkrw };
84557f712bSkrw 
85e485502dSkrw /*
86e485502dSkrw  * NOTE! Changing partition sizes in the space_allocation tables
87e485502dSkrw  *       requires corresponding updates to the *.ok files in
88e485502dSkrw  *	 /usr/src/regress/sbin/disklabel.
89e485502dSkrw  */
90e485502dSkrw 
918dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */
92a2c1f847Shenning struct space_allocation alloc_big[] = {
93d190517aSotto 	{  MEG(150),         GIG(1),   5, "/"		},
94559340afSotto 	{   MEG(80),       MEG(256),  10, "swap"	},
954ab111d2Sderaadt 	{  MEG(120),         GIG(4),   8, "/tmp"	},
9692adb55fSderaadt 	{   MEG(80),         GIG(4),  13, "/var"	},
97cc2b79a5Smbuhl 	{ MEG(1500),        GIG(30),  10, "/usr"	},
98ecf06799Sajacoutot 	{  MEG(384),         GIG(1),   3, "/usr/X11R6"	},
9997f090a4Ssolene 	{    GIG(1),        GIG(20),  15, "/usr/local"	},
100*854d339cSjan 	{    GIG(2),         GIG(5),   2, "/usr/src"	},
101d6b9791fSbluhm 	{    GIG(5),         GIG(6),   4, "/usr/obj"	},
10226e633f4Sotto 	{    GIG(1),       GIG(300),  30, "/home"	}
1034ab111d2Sderaadt 	/* Anything beyond this leave for the user to decide */
1048dde8bb6Sotto };
1058dde8bb6Sotto 
106a2c1f847Shenning struct space_allocation alloc_medium[] = {
107905e8239Sderaadt 	{  MEG(800),         GIG(2),   5, "/"		},
1088dde8bb6Sotto 	{   MEG(80),       MEG(256),  10, "swap"	},
109ad1fb99dSphessler 	{ MEG(1300),         GIG(3),  78, "/usr"	},
110905e8239Sderaadt 	{  MEG(256),         GIG(2),   7, "/home"	}
1118dde8bb6Sotto };
1128dde8bb6Sotto 
113a2c1f847Shenning struct space_allocation alloc_small[] = {
11492adb55fSderaadt 	{  MEG(700),         GIG(4),  95, "/"		},
1158dde8bb6Sotto 	{    MEG(1),       MEG(256),   5, "swap"	}
1168dde8bb6Sotto };
1178dde8bb6Sotto 
118a2c1f847Shenning struct space_allocation alloc_stupid[] = {
1198dde8bb6Sotto 	{    MEG(1),      MEG(2048), 100, "/"		}
1208dde8bb6Sotto };
1218dde8bb6Sotto 
122b2813ff1Sderaadt #ifndef nitems
123b2813ff1Sderaadt #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
124b2813ff1Sderaadt #endif
125b2813ff1Sderaadt 
126a2c1f847Shenning struct alloc_table {
127a2c1f847Shenning 	struct space_allocation *table;
1288a862940Sderaadt 	int sz;
129a2c1f847Shenning };
130a2c1f847Shenning 
131a2c1f847Shenning struct alloc_table alloc_table_default[] = {
1328dde8bb6Sotto 	{ alloc_big,	nitems(alloc_big) },
1338dde8bb6Sotto 	{ alloc_medium,	nitems(alloc_medium) },
1348dde8bb6Sotto 	{ alloc_small,	nitems(alloc_small) },
1358dde8bb6Sotto 	{ alloc_stupid,	nitems(alloc_stupid) }
136557f712bSkrw };
137a2c1f847Shenning struct alloc_table *alloc_table = alloc_table_default;
138f55524eaSsthen int alloc_table_nitems = 4;
139557f712bSkrw 
1401cc333d2Skrw void	edit_packname(struct disklabel *);
141c0bc1f19Skrw void	editor_resize(struct disklabel *, const char *);
142c0bc1f19Skrw void	editor_add(struct disklabel *, const char *);
143c0bc1f19Skrw void	editor_change(struct disklabel *, const char *);
14443ba7787Skrw u_int64_t editor_countfree(const struct disklabel *);
145c0bc1f19Skrw void	editor_delete(struct disklabel *, const char *);
1464d812bb6Slum void	editor_help(void);
147c0bc1f19Skrw void	editor_modify(struct disklabel *, const char *);
14841d86e10Skrw void	editor_name(const struct disklabel *, const char *);
149b228e876Smiod char	*getstring(const char *, const char *, const char *);
15043ba7787Skrw u_int64_t getuint64(const struct disklabel *, char *, char *, u_int64_t,
15140b226e8Skrw     u_int64_t, int *);
152c0bc1f19Skrw u_int64_t getnumber(const char *, const char *, u_int32_t, u_int32_t);
15378ff4c86Skrw int	getpartno(const struct disklabel *, const char *, const char *);
1541f0f871dSkrw int	has_overlap(struct disklabel *);
155c72b5b24Smillert int	partition_cmp(const void *, const void *);
15643ba7787Skrw const struct partition **sort_partitions(const struct disklabel *, int);
15743ba7787Skrw void	find_bounds(const struct disklabel *);
1589fdcb4d6Skrw void	set_bounds(struct disklabel *);
15969a6ffbcSjsing void	set_duid(struct disklabel *);
160728b9255Skrw int	set_fragblock(struct disklabel *, int);
161ab2017adSkrw const struct diskchunk *free_chunks(const struct disklabel *, int);
162c72b5b24Smillert int	micmp(const void *, const void *);
163c72b5b24Smillert int	mpequal(char **, char **);
164c72b5b24Smillert int	get_fstype(struct disklabel *, int);
16541d86e10Skrw int	get_mp(const struct disklabel *, int);
166604d3bdeSkrw int	get_offset(struct disklabel *, int);
1679fdcb4d6Skrw int	get_size(struct disklabel *, int);
1689fdcb4d6Skrw void	zero_partitions(struct disklabel *);
16943ba7787Skrw u_int64_t max_partition_size(const struct disklabel *, int);
17043ba7787Skrw void	display_edit(const struct disklabel *, char);
17143ba7787Skrw void	psize(u_int64_t sz, char unit, const struct disklabel *lp);
17258c7d7acSnaddy char	*get_token(char **);
173a2c1f847Shenning int	apply_unit(double, u_char, u_int64_t *);
174a2c1f847Shenning int	parse_sizespec(const char *, double *, char **);
175a2c1f847Shenning int	parse_sizerange(char *, u_int64_t *, u_int64_t *);
176a2c1f847Shenning int	parse_pct(char *, int *);
17740b226e8Skrw int	alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int);
178756bef51Skrw int	allocate_space(struct disklabel *, const struct alloc_table *);
179756bef51Skrw void	allocate_physmemincr(struct space_allocation *);
180756bef51Skrw int	allocate_partition(struct disklabel *, struct space_allocation *);
181756bef51Skrw const struct diskchunk *allocate_diskchunk(const struct disklabel *,
182756bef51Skrw     const struct space_allocation *);
18396a888c6Smillert 
1841e0ad43cSotto static u_int64_t starting_sector;
1851e0ad43cSotto static u_int64_t ending_sector;
186c2c8bb79Skrw static int resizeok;
1876fe57b42Smillert 
1886fe57b42Smillert /*
1894d4a335eSkrw  * Simple partition editor.
1906fe57b42Smillert  */
1916fe57b42Smillert int
editor(int f)192d6d80bb0Skrw editor(int f)
1936fe57b42Smillert {
194d6d80bb0Skrw 	struct disklabel origlabel, lastlabel, tmplabel, newlab = lab;
19596a888c6Smillert 	struct partition *pp;
1966fe57b42Smillert 	FILE *fp;
1976fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
19834ae4198Skrw 	char **omountpoints = NULL;
1994f3bbbf0Skrw 	char **origmountpoints = NULL, **tmpmountpoints = NULL;
2007e28fb0fSderaadt 	int i, error = 0;
201bd6726faSmillert 
202bd6726faSmillert 	/* Alloc and init mount point info */
20334ae4198Skrw 	if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
2044f3bbbf0Skrw 	    !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
205bd6726faSmillert 	    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
206b7cc13deSkrw 		err(1, NULL);
2076fe57b42Smillert 
208d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
209d6d80bb0Skrw 	find_bounds(&newlab);
210d09f3941Smillert 
21196a888c6Smillert 	/* Make sure there is no partition overlap. */
212d6d80bb0Skrw 	if (has_overlap(&newlab))
2136fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
2146fe57b42Smillert 
21596a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
216d6d80bb0Skrw 	pp = &newlab.d_partitions[RAW_PART];
217d4e23fe7Skrw 	if (newlab.d_npartitions <= RAW_PART || DL_GETPSIZE(pp) == 0) {
21896a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
219d4e23fe7Skrw 		if (newlab.d_npartitions <= RAW_PART)
220d4e23fe7Skrw 			newlab.d_npartitions = RAW_PART + 1;
22134af67a3Sotto 		DL_SETPOFFSET(pp, 0);
222d6d80bb0Skrw 		DL_SETPSIZE(pp, DL_GETDSIZE(&newlab));
22396a888c6Smillert 		pp->p_fstype = FS_UNUSED;
224ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
22596a888c6Smillert 	}
2260f820bbbSmillert 
227fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
2284bf1fc9dSotto 	if ((newlab.d_flags & D_VENDOR) && !quiet) {
229fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
230fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
231fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
232fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
233fc1a4cc6Sderaadt 	}
2346fe57b42Smillert #endif
2356fe57b42Smillert 
23693160b9bSkrw 	/* Save the (U|u)ndo labels and mountpoints. */
23793160b9bSkrw 	mpcopy(origmountpoints, mountpoints);
238d6d80bb0Skrw 	origlabel = newlab;
239d6d80bb0Skrw 	lastlabel = newlab;
24034ae4198Skrw 
24134ae4198Skrw 	puts("Label editor (enter '?' for help at any prompt)");
2426fe57b42Smillert 	for (;;) {
243953cd4efSkrw 		fprintf(stdout, "%s%s> ", dkname,
244953cd4efSkrw 		    (memcmp(&lab, &newlab, sizeof(newlab)) == 0) ? "" : "*");
2456e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2466e0becc5Smillert 			putchar('\n');
2476e0becc5Smillert 			buf[0] = 'q';
2486e0becc5Smillert 			buf[1] = '\0';
2496e0becc5Smillert 		}
250260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
251260513deSmillert 			continue;
252260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2536fe57b42Smillert 
2544f3bbbf0Skrw 		if ((*cmd != 'u') && (*cmd != 'U')) {
2554f3bbbf0Skrw 			/*
2564f3bbbf0Skrw 			 * Save undo info in case the command tries to make
2574f3bbbf0Skrw 			 * changes but decides not to.
2584f3bbbf0Skrw 			 */
2594f3bbbf0Skrw 			tmplabel = lastlabel;
260d6d80bb0Skrw 			lastlabel = newlab;
2614f3bbbf0Skrw 			mpcopy(tmpmountpoints, omountpoints);
2624f3bbbf0Skrw 			mpcopy(omountpoints, mountpoints);
2634f3bbbf0Skrw 		}
2646fe57b42Smillert 
2654f3bbbf0Skrw 		switch (*cmd) {
2666fe57b42Smillert 		case '?':
267ea37abd3Sderaadt 		case 'h':
2684d812bb6Slum 			editor_help();
2696fe57b42Smillert 			break;
2706fe57b42Smillert 
271557f712bSkrw 		case 'A':
27290b0764fSkrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == -1) {
27390b0764fSkrw 				warn("DIOCGPDINFO");
27490b0764fSkrw 				newlab = lastlabel;
27590b0764fSkrw 			} else {
276953cd4efSkrw 				int oquiet = quiet;
2774bf1fc9dSotto 				aflag = 1;
278953cd4efSkrw 				quiet = 0;
279d6d80bb0Skrw 				editor_allocspace(&newlab);
28040b226e8Skrw 				quiet = oquiet;
28190b0764fSkrw 			}
282557f712bSkrw 			break;
2836fe57b42Smillert 		case 'a':
284d6d80bb0Skrw 			editor_add(&newlab, arg);
28596a888c6Smillert 			break;
28696a888c6Smillert 
28796a888c6Smillert 		case 'b':
288d6d80bb0Skrw 			set_bounds(&newlab);
2896fe57b42Smillert 			break;
2906fe57b42Smillert 
2916fe57b42Smillert 		case 'c':
292d6d80bb0Skrw 			editor_change(&newlab, arg);
2936fe57b42Smillert 			break;
2946fe57b42Smillert 
2959afbe9eeSmillert 		case 'D':
29690b0764fSkrw 			if (ioctl(f, DIOCGPDINFO, &newlab) == -1)
29790b0764fSkrw 				warn("DIOCGPDINFO");
29890b0764fSkrw 			else {
29971bba4ecSkrw 				dflag = 1;
30093160b9bSkrw 				for (i = 0; i < MAXPARTITIONS; i++) {
30193160b9bSkrw 					free(mountpoints[i]);
30293160b9bSkrw 					mountpoints[i] = NULL;
30393160b9bSkrw 				}
30490b0764fSkrw 			}
3059afbe9eeSmillert 			break;
3069afbe9eeSmillert 
3076fe57b42Smillert 		case 'd':
308d6d80bb0Skrw 			editor_delete(&newlab, arg);
3096fe57b42Smillert 			break;
3106fe57b42Smillert 
3119afbe9eeSmillert 		case 'e':
3121cc333d2Skrw 			edit_packname(&newlab);
3139afbe9eeSmillert 			break;
3149afbe9eeSmillert 
3150d63cfbaSjsing 		case 'i':
316d6d80bb0Skrw 			set_duid(&newlab);
3170d63cfbaSjsing 			break;
3180d63cfbaSjsing 
3196fe57b42Smillert 		case 'm':
320d6d80bb0Skrw 			editor_modify(&newlab, arg);
321bd6726faSmillert 			break;
322bd6726faSmillert 
323bd6726faSmillert 		case 'n':
3245c79e1cfSkrw 			if (!fstabfile) {
325bd6726faSmillert 				fputs("This option is not valid when run "
3266b27d9e0Sjmc 				    "without the -F or -f flags.\n", stderr);
327bd6726faSmillert 				break;
328bd6726faSmillert 			}
329d6d80bb0Skrw 			editor_name(&newlab, arg);
3306fe57b42Smillert 			break;
3316fe57b42Smillert 
3326fe57b42Smillert 		case 'p':
3337ad973c1Skrw 			display_edit(&newlab, arg ? *arg : 0);
3346fe57b42Smillert 			break;
3356fe57b42Smillert 
336aff3f969Sotto 		case 'l':
337d6d80bb0Skrw 			display(stdout, &newlab, arg ? *arg : 0, 0);
338aff3f969Sotto 			break;
339aff3f969Sotto 
340508086e9Smillert 		case 'M': {
341508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
34245decb36Sderaadt 			char *pager, *comm = NULL;
343e7936562Sderaadt 			extern const u_char manpage[];
34408f8e31fSotto 			extern const int manpage_sz;
3455d12b01bSderaadt 
346489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
347508086e9Smillert 				pager = _PATH_LESS;
34808f8e31fSotto 
34945decb36Sderaadt 			if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 &&
35045decb36Sderaadt 			    (fp = popen(comm, "w")) != NULL) {
35108f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3525d12b01bSderaadt 				pclose(fp);
353508086e9Smillert 			} else
354508086e9Smillert 				warn("unable to execute %s", pager);
355508086e9Smillert 
35645decb36Sderaadt 			free(comm);
357508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3585d12b01bSderaadt 			break;
359508086e9Smillert 		}
3605d12b01bSderaadt 
3616fe57b42Smillert 		case 'q':
36269220492Smillert 			if (donothing) {
36369220492Smillert 				puts("In no change mode, not writing label.");
3647e28fb0fSderaadt 				goto done;
36569220492Smillert 			}
36693160b9bSkrw 
36771bba4ecSkrw 			/*
36893160b9bSkrw 			 * If we haven't changed the original label, and it
36993160b9bSkrw 			 * wasn't a default label or an auto-allocated label,
37093160b9bSkrw 			 * there is no need to do anything before exiting. Note
37193160b9bSkrw 			 * that 'w' will reset dflag and aflag to allow 'q' to
37293160b9bSkrw 			 * exit without further questions.
37371bba4ecSkrw 			 */
374ab20a3eaSkrw 			if (!dflag && !aflag &&
375d6d80bb0Skrw 			    memcmp(&lab, &newlab, sizeof(newlab)) == 0) {
376bd6726faSmillert 				puts("No label changes.");
377d6d80bb0Skrw 				/* Save mountpoint info. */
378d6d80bb0Skrw 				mpsave(&newlab);
3797e28fb0fSderaadt 				goto done;
3806fe57b42Smillert 			}
3816fe57b42Smillert 			do {
382d0e67762Smillert 				arg = getstring("Write new label?",
383d0e67762Smillert 				    "Write the modified label to disk?",
384d0e67762Smillert 				    "y");
385025f5691Sderaadt 			} while (arg && tolower((unsigned char)*arg) != 'y' &&
386025f5691Sderaadt 			    tolower((unsigned char)*arg) != 'n');
387025f5691Sderaadt 			if (arg && tolower((unsigned char)*arg) == 'y') {
38840bba581Skrw 				if (writelabel(f, &newlab) == 0) {
389d6d80bb0Skrw 					newlab = lab; /* lab now has UID info */
3907e28fb0fSderaadt 					goto done;
3916fe57b42Smillert 				}
392d0e67762Smillert 				warnx("unable to write label");
393d0e67762Smillert 			}
3947e28fb0fSderaadt 			error = 1;
3957e28fb0fSderaadt 			goto done;
3966fe57b42Smillert 			/* NOTREACHED */
3976fe57b42Smillert 			break;
3986fe57b42Smillert 
3996aaa4aabSotto 		case 'R':
400c2c8bb79Skrw 			if (aflag && resizeok)
401d6d80bb0Skrw 				editor_resize(&newlab, arg);
4026aaa4aabSotto 			else
4036aaa4aabSotto 				fputs("Resize only implemented for auto "
404fc6e9c48Sotto 				    "allocated labels\n", stderr);
4056aaa4aabSotto 			break;
4066aaa4aabSotto 
40725f9c360Skrw 		case 'r': {
408d9355c7dSkrw 			const struct diskchunk *chunk;
409d9355c7dSkrw 			uint64_t total = 0;
4109fdcb4d6Skrw 			/* Display free space. */
411411a261cSkrw 			chunk = free_chunks(&newlab, -1);
412d9355c7dSkrw 			for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
413b46f7512Skrw 				total += CHUNKSZ(chunk);
41425f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
41525f9c360Skrw 				    "(%16llu)\n",
416d9355c7dSkrw 				    chunk->start, chunk->stop - 1,
417b46f7512Skrw 				    CHUNKSZ(chunk));
418d9355c7dSkrw 			}
419d9355c7dSkrw 			fprintf(stderr, "Total free sectors: %llu.\n", total);
420c0bdc608Smillert 			break;
42125f9c360Skrw 		}
422c0bdc608Smillert 
4236fe57b42Smillert 		case 's':
4246fe57b42Smillert 			if (arg == NULL) {
425c33fcabaSmillert 				arg = getstring("Filename",
4266fe57b42Smillert 				    "Name of the file to save label into.",
4276fe57b42Smillert 				    NULL);
428e97229a3Scnst 				if (arg == NULL || *arg == '\0')
4296fe57b42Smillert 					break;
4306fe57b42Smillert 			}
4316fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
4326fe57b42Smillert 				warn("cannot open %s", arg);
4336fe57b42Smillert 			} else {
434d6d80bb0Skrw 				display(fp, &newlab, 0, 1);
4356fe57b42Smillert 				(void)fclose(fp);
4366fe57b42Smillert 			}
4376fe57b42Smillert 			break;
4386fe57b42Smillert 
4394f3bbbf0Skrw 		case 'U':
44093160b9bSkrw 			/*
441430e1380Skrw 			 * If we allow 'U' repeatedly, information would be
442430e1380Skrw 			 * lost. This way multiple 'U's followed by 'u' will
443430e1380Skrw 			 * undo the 'U's.
44493160b9bSkrw 			 */
445d6d80bb0Skrw 			if (memcmp(&newlab, &origlabel, sizeof(newlab)) ||
44693160b9bSkrw 			    !mpequal(mountpoints, origmountpoints)) {
447d6d80bb0Skrw 				tmplabel = newlab;
448d6d80bb0Skrw 				newlab = origlabel;
4494f3bbbf0Skrw 				lastlabel = tmplabel;
4504f3bbbf0Skrw 				mpcopy(tmpmountpoints, mountpoints);
4514f3bbbf0Skrw 				mpcopy(mountpoints, origmountpoints);
4524f3bbbf0Skrw 				mpcopy(omountpoints, tmpmountpoints);
4534f3bbbf0Skrw 			}
45493160b9bSkrw 			puts("Original label and mount points restored.");
4554f3bbbf0Skrw 			break;
4564f3bbbf0Skrw 
4576fe57b42Smillert 		case 'u':
458d6d80bb0Skrw 			tmplabel = newlab;
459d6d80bb0Skrw 			newlab = lastlabel;
4606fe57b42Smillert 			lastlabel = tmplabel;
4614f3bbbf0Skrw 			mpcopy(tmpmountpoints, mountpoints);
462bd6726faSmillert 			mpcopy(mountpoints, omountpoints);
4634f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
4646fe57b42Smillert 			puts("Last change undone.");
4656fe57b42Smillert 			break;
4666fe57b42Smillert 
467040947cfSmillert 		case 'w':
468bd6726faSmillert 			if (donothing)  {
469040947cfSmillert 				puts("In no change mode, not writing label.");
470bd6726faSmillert 				break;
471bd6726faSmillert 			}
47293160b9bSkrw 
47341f684b9Skrw 			/* Write label to disk. */
47440bba581Skrw 			if (writelabel(f, &newlab) != 0)
475040947cfSmillert 				warnx("unable to write label");
47671bba4ecSkrw 			else {
477ab20a3eaSkrw 				dflag = aflag = 0;
478d6d80bb0Skrw 				newlab = lab; /* lab now has UID info */
47971bba4ecSkrw 			}
480040947cfSmillert 			break;
481040947cfSmillert 
4826fe57b42Smillert 		case 'x':
4837e28fb0fSderaadt 			goto done;
4846fe57b42Smillert 			break;
4856fe57b42Smillert 
4869afbe9eeSmillert 		case 'z':
487d6d80bb0Skrw 			zero_partitions(&newlab);
4886fe57b42Smillert 			break;
4896fe57b42Smillert 
4909afbe9eeSmillert 		case '\n':
4916fe57b42Smillert 			break;
4926fe57b42Smillert 
4936fe57b42Smillert 		default:
4946fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4956fe57b42Smillert 			break;
4966fe57b42Smillert 		}
4974f3bbbf0Skrw 
4984f3bbbf0Skrw 		/*
4994f3bbbf0Skrw 		 * If no changes were made to label or mountpoints, then
5004f3bbbf0Skrw 		 * restore undo info.
5014f3bbbf0Skrw 		 */
502d6d80bb0Skrw 		if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 &&
50393160b9bSkrw 		    (mpequal(mountpoints, omountpoints))) {
5044f3bbbf0Skrw 			lastlabel = tmplabel;
5054f3bbbf0Skrw 			mpcopy(omountpoints, tmpmountpoints);
5064f3bbbf0Skrw 		}
5076fe57b42Smillert 	}
5087e28fb0fSderaadt done:
509e46ff49bSkrw 	mpfree(omountpoints, DISCARD);
510e46ff49bSkrw 	mpfree(origmountpoints, DISCARD);
511e46ff49bSkrw 	mpfree(tmpmountpoints, DISCARD);
512bb12209fSkrw 	return error;
5136fe57b42Smillert }
5146fe57b42Smillert 
5156fe57b42Smillert /*
516557f712bSkrw  * Allocate all disk space according to standard recommendations for a
517557f712bSkrw  * root disk.
518557f712bSkrw  */
519185664b4Sotto int
editor_allocspace(struct disklabel * lp_org)5208dde8bb6Sotto editor_allocspace(struct disklabel *lp_org)
521557f712bSkrw {
522756bef51Skrw 	struct disklabel label;
5233c750429Skrw 	struct partition *pp;
524756bef51Skrw 	u_int64_t pstart, pend;
525756bef51Skrw 	int i;
5268dde8bb6Sotto 
52734ae4198Skrw 	/* How big is the OpenBSD portion of the disk?  */
5288dde8bb6Sotto 	find_bounds(lp_org);
529557f712bSkrw 
530c2c8bb79Skrw 	resizeok = 1;
531fc6e9c48Sotto 	for (i = 0;  i < MAXPARTITIONS; i++) {
532c2c8bb79Skrw 		if (i == RAW_PART)
533c2c8bb79Skrw 			continue;
5343c750429Skrw 		pp = &lp_org->d_partitions[i];
5353c750429Skrw 		if (DL_GETPSIZE(pp) == 0 || pp->p_fstype == FS_UNUSED)
5363c750429Skrw 			continue;
5373c750429Skrw 		pstart = DL_GETPOFFSET(pp);
5383c750429Skrw 		pend = pstart + DL_GETPSIZE(pp);
539114ca9f3Skrw 		if (((pstart >= starting_sector && pstart < ending_sector) ||
540114ca9f3Skrw 		    (pend > starting_sector && pend <= ending_sector)))
541114ca9f3Skrw 			resizeok = 0; /* Part of OBSD area is in use! */
542fc6e9c48Sotto 	}
543fc6e9c48Sotto 
544756bef51Skrw 	for (i = 0; i < alloc_table_nitems; i++) {
545756bef51Skrw 		memcpy(&label, lp_org, sizeof(label));
546756bef51Skrw 		if (allocate_space(&label, &alloc_table[i]) == 0) {
547756bef51Skrw 			memcpy(lp_org, &label, sizeof(struct disklabel));
548756bef51Skrw 			return 0;
549756bef51Skrw 		}
550756bef51Skrw 	}
551756bef51Skrw 
552598ec681Skrw 	return 1;
5538dde8bb6Sotto }
5548dde8bb6Sotto 
555756bef51Skrw const struct diskchunk *
allocate_diskchunk(const struct disklabel * lp,const struct space_allocation * sa)556756bef51Skrw allocate_diskchunk(const struct disklabel *lp,
557756bef51Skrw     const struct space_allocation *sa)
558756bef51Skrw {
559756bef51Skrw 	const struct diskchunk *chunk;
560756bef51Skrw 	static struct diskchunk largest;
561756bef51Skrw 	uint64_t maxstop;
562557f712bSkrw 
563756bef51Skrw 	largest.start = largest.stop = 0;
564557f712bSkrw 
565411a261cSkrw 	chunk = free_chunks(lp, -1);
566cfdfc664Skrw 	for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
567756bef51Skrw 		if (CHUNKSZ(chunk) > CHUNKSZ(&largest))
568756bef51Skrw 			largest = *chunk;
569756bef51Skrw 	}
570756bef51Skrw 	maxstop = largest.start + DL_BLKTOSEC(lp, sa->maxsz);
571756bef51Skrw 	if (maxstop > largest.stop)
572756bef51Skrw 		maxstop = largest.stop;
57334ae4198Skrw #ifdef SUN_CYLCHECK
57434ae4198Skrw 	if (lp->d_flags & D_VENDOR) {
575756bef51Skrw 		largest.start = ROUNDUP(largest.start, lp->d_secpercyl);
576756bef51Skrw 		maxstop = ROUNDUP(maxstop, lp->d_secpercyl);
577756bef51Skrw 		if (maxstop > largest.stop)
578756bef51Skrw 			maxstop -= lp->d_secpercyl;
579756bef51Skrw 		if (largest.start >= maxstop)
580756bef51Skrw 			largest.start = largest.stop = maxstop = 0;
58134ae4198Skrw 	}
58234ae4198Skrw #endif
583756bef51Skrw 	if (maxstop < largest.stop)
584756bef51Skrw 		largest.stop = maxstop;
585756bef51Skrw 	if (CHUNKSZ(&largest) < DL_BLKTOSEC(lp, sa->minsz))
586756bef51Skrw 		return NULL;
587756bef51Skrw 
588756bef51Skrw 	return &largest;
589859c13c7Skrw }
590859c13c7Skrw 
591756bef51Skrw int
allocate_partition(struct disklabel * lp,struct space_allocation * sa)592756bef51Skrw allocate_partition(struct disklabel *lp, struct space_allocation *sa)
593756bef51Skrw {
594756bef51Skrw 	const struct diskchunk *chunk;
595756bef51Skrw 	struct partition *pp;
596756bef51Skrw 	unsigned int partno;
59759c4e6f1Skrw 
598756bef51Skrw 	for (partno = 0; partno < nitems(lp->d_partitions); partno++) {
599756bef51Skrw 		if (partno == RAW_PART)
600756bef51Skrw 			continue;
601756bef51Skrw 		pp = &lp->d_partitions[partno];
602756bef51Skrw 		if (DL_GETPSIZE(pp) == 0 || pp->p_fstype == FS_UNUSED)
603756bef51Skrw 			break;
604557f712bSkrw 	}
605756bef51Skrw 	if (partno >= nitems(lp->d_partitions))
606756bef51Skrw 		return 1;		/* No free partition. */
60734ae4198Skrw 
608756bef51Skrw 	/* Find appropriate chunk of free space. */
609756bef51Skrw 	chunk = allocate_diskchunk(lp, sa);
610756bef51Skrw 	if (chunk == NULL)
611756bef51Skrw 		return 1;
612756bef51Skrw 
613756bef51Skrw 	if (strcasecmp(sa->mp, "raid") == 0)
6144536786eSkrw 		pp->p_fstype = FS_RAID;
615756bef51Skrw 	else if (strcasecmp(sa->mp, "swap") == 0)
61634ae4198Skrw 		pp->p_fstype = FS_SWAP;
617756bef51Skrw 	else if (sa->mp[0] == '/')
61834ae4198Skrw 		pp->p_fstype = FS_BSDFFS;
619756bef51Skrw 	else
620756bef51Skrw 		return 1;
621756bef51Skrw 
622756bef51Skrw 	DL_SETPSIZE(pp, chunk->stop - chunk->start);
623756bef51Skrw 	DL_SETPOFFSET(pp, chunk->start);
624756bef51Skrw 
625756bef51Skrw 	if (pp->p_fstype == FS_BSDFFS && DL_GETPSIZE(pp) > 0) {
626756bef51Skrw 		mountpoints[partno] = strdup(sa->mp);
627756bef51Skrw 		if (mountpoints[partno] == NULL)
628756bef51Skrw 			err(1, NULL);
629756bef51Skrw 		if (set_fragblock(lp, partno))
630d68164a2Skrw 			return 1;
631d68164a2Skrw 	}
632756bef51Skrw 
633756bef51Skrw 	return 0;
634756bef51Skrw }
635756bef51Skrw 
636756bef51Skrw void
allocate_physmemincr(struct space_allocation * sa)637756bef51Skrw allocate_physmemincr(struct space_allocation *sa)
638756bef51Skrw {
639756bef51Skrw 	u_int64_t memblks;
640756bef51Skrw 	extern int64_t physmem;
641756bef51Skrw 
642756bef51Skrw 	if (physmem == 0)
643756bef51Skrw 		return;
644756bef51Skrw 
645756bef51Skrw 	memblks = physmem / DEV_BSIZE;
646756bef51Skrw 	if (strcasecmp(sa->mp, "swap") == 0) {
647756bef51Skrw 		if (memblks < MEG(256))
648756bef51Skrw 			sa->minsz = sa->maxsz = 2 * memblks;
649756bef51Skrw 		else
650756bef51Skrw 			sa->maxsz += memblks;
651756bef51Skrw 	} else if (strcasecmp(sa->mp, "/var") == 0) {
652756bef51Skrw 		sa->maxsz += 2 * memblks;
653557f712bSkrw 	}
654557f712bSkrw }
655557f712bSkrw 
656756bef51Skrw int
allocate_space(struct disklabel * lp,const struct alloc_table * alloc_table)657756bef51Skrw allocate_space(struct disklabel *lp, const struct alloc_table *alloc_table)
658756bef51Skrw {
659756bef51Skrw 	struct space_allocation sa[MAXPARTITIONS];
660756bef51Skrw 	u_int64_t maxsz, xtrablks;
661756bef51Skrw 	int i;
662756bef51Skrw 
663756bef51Skrw 	xtrablks = DL_SECTOBLK(lp, editor_countfree(lp));
664756bef51Skrw 	memset(sa, 0, sizeof(sa));
665756bef51Skrw 	for (i = 0; i < alloc_table->sz; i++) {
666756bef51Skrw 		sa[i] = alloc_table->table[i];
667756bef51Skrw 		if (alloc_table->table == alloc_big)
668756bef51Skrw 			allocate_physmemincr(&sa[i]);
669756bef51Skrw 		if (xtrablks < sa[i].minsz)
670756bef51Skrw 			return 1;	/* Too few free blocks. */
671756bef51Skrw 		xtrablks -= sa[i].minsz;
672756bef51Skrw 	}
673756bef51Skrw 	sa[alloc_table->sz - 1].rate = 100; /* Last allocation is greedy. */
674756bef51Skrw 
675756bef51Skrw 	for (i = lp->d_npartitions; i < MAXPARTITIONS; i++) {
676756bef51Skrw 		if (i == RAW_PART)
677756bef51Skrw 			continue;
678756bef51Skrw 		memset(&lp->d_partitions[i], 0, sizeof(lp->d_partitions[i]));
679756bef51Skrw 	}
680756bef51Skrw 	lp->d_npartitions = MAXPARTITIONS;
681756bef51Skrw 
682756bef51Skrw 	mpfree(mountpoints, KEEP);
683756bef51Skrw 	for (i = 0; i < alloc_table->sz; i++) {
684775a2993Skrw 		if (sa[i].rate == 100)
685775a2993Skrw 			maxsz = sa[i].minsz + xtrablks;
686775a2993Skrw 		else
687756bef51Skrw 			maxsz = sa[i].minsz + (xtrablks / 100) * sa[i].rate;
688756bef51Skrw 		if (maxsz < sa[i].maxsz)
689756bef51Skrw 			sa[i].maxsz = maxsz;
690756bef51Skrw 		if (allocate_partition(lp, &sa[i])) {
691756bef51Skrw 			mpfree(mountpoints, KEEP);
692756bef51Skrw 			return 1;
693756bef51Skrw 		}
694756bef51Skrw 	}
695756bef51Skrw 
696185664b4Sotto 	return 0;
697557f712bSkrw }
698557f712bSkrw 
699557f712bSkrw /*
7006aaa4aabSotto  * Resize a partition, moving all subsequent partitions
7016aaa4aabSotto  */
7026aaa4aabSotto void
editor_resize(struct disklabel * lp,const char * p)703c0bc1f19Skrw editor_resize(struct disklabel *lp, const char *p)
7046aaa4aabSotto {
7056aaa4aabSotto 	struct disklabel label;
7066aaa4aabSotto 	struct partition *pp, *prev;
707914b3475Skrw 	u_int64_t ui, sz, off;
70877370cdaSkrw 	int partno, i, flags, shrunk;
7096aaa4aabSotto 
7106aaa4aabSotto 	label = *lp;
7116aaa4aabSotto 
71278ff4c86Skrw 	if ((partno = getpartno(&label, p, "resize")) == -1)
7136aaa4aabSotto 		return;
7146aaa4aabSotto 
7156aaa4aabSotto 	pp = &label.d_partitions[partno];
716fc6e9c48Sotto 	sz = DL_GETPSIZE(pp);
717fc6e9c48Sotto 	if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) {
718fc6e9c48Sotto 		fputs("Cannot resize spoofed partition\n", stderr);
719fc6e9c48Sotto 		return;
720fc6e9c48Sotto 	}
72140b226e8Skrw 	flags = DO_CONVERSIONS;
722914b3475Skrw 	ui = getuint64(lp, "[+|-]new size (with unit)",
723e0befca8Skrw 	    "new size or amount to grow (+) or shrink (-) partition including "
72440b226e8Skrw 	    "unit", sz, sz + editor_countfree(lp), &flags);
7256aaa4aabSotto 
726914b3475Skrw 	if (ui == CMD_ABORTED)
7276aaa4aabSotto 		return;
728914b3475Skrw 	else if (ui == CMD_BADVALUE)
7299f0bdc2aSkrw 		return;
730914b3475Skrw 	else if (ui == 0) {
7311298f28aSkrw 		fputs("The size must be > 0 sectors\n", stderr);
7321298f28aSkrw 		return;
7336aaa4aabSotto 	}
7346aaa4aabSotto 
7356aaa4aabSotto #ifdef SUN_CYLCHECK
7367233a2b0Skrw 	if (lp->d_flags & D_VENDOR)
7377233a2b0Skrw 		ui = ROUNDUP(ui, lp->d_secpercyl);
7386aaa4aabSotto #endif
739914b3475Skrw 	if (DL_GETPOFFSET(pp) + ui > ending_sector) {
7406aaa4aabSotto 		fputs("Amount too big\n", stderr);
7416aaa4aabSotto 		return;
7426aaa4aabSotto 	}
7436aaa4aabSotto 
744914b3475Skrw 	DL_SETPSIZE(pp, ui);
745d68164a2Skrw 	pp->p_fragblock = 0;
746728b9255Skrw 	if (set_fragblock(&label, partno) == 1)
747d68164a2Skrw 		return;
7486aaa4aabSotto 
7496aaa4aabSotto 	/*
7506aaa4aabSotto 	 * Pack partitions above the resized partition, leaving unused
751c7e00dc5Skrw 	 * partitions alone.
7526aaa4aabSotto 	 */
75377370cdaSkrw 	shrunk = -1;
7546aaa4aabSotto 	prev = pp;
7556aaa4aabSotto 	for (i = partno + 1; i < MAXPARTITIONS; i++) {
7566aaa4aabSotto 		if (i == RAW_PART)
7576aaa4aabSotto 			continue;
758fc6e9c48Sotto 		pp = &label.d_partitions[i];
759fc6e9c48Sotto 		if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP)
760fc6e9c48Sotto 			continue;
761fc6e9c48Sotto 		sz = DL_GETPSIZE(pp);
7626aaa4aabSotto 		if (sz == 0)
7636aaa4aabSotto 			continue;
7646aaa4aabSotto 
7656aaa4aabSotto 		off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev);
7666aaa4aabSotto 
7676aaa4aabSotto 		if (off < ending_sector) {
7686aaa4aabSotto 			DL_SETPOFFSET(pp, off);
7696aaa4aabSotto 			if (off + DL_GETPSIZE(pp) > ending_sector) {
7706aaa4aabSotto 				DL_SETPSIZE(pp, ending_sector - off);
7714ef23daeSkrw 				pp->p_fragblock = 0;
772728b9255Skrw 				if (set_fragblock(&label, i) == 1)
773d68164a2Skrw 					return;
77477370cdaSkrw 				shrunk = i;
7756aaa4aabSotto 			}
7766aaa4aabSotto 		} else {
77777370cdaSkrw 			fputs("Amount too big\n", stderr);
7786aaa4aabSotto 			return;
7796aaa4aabSotto 		}
7806aaa4aabSotto 		prev = pp;
7816aaa4aabSotto 	}
78277370cdaSkrw 
78377370cdaSkrw 	if (shrunk != -1)
78477370cdaSkrw 		fprintf(stderr, "Partition %c shrunk to %llu sectors to make "
78577370cdaSkrw 		    "room\n", 'a' + shrunk,
78677370cdaSkrw 		    DL_GETPSIZE(&label.d_partitions[shrunk]));
7876aaa4aabSotto 	*lp = label;
7886aaa4aabSotto }
7896aaa4aabSotto 
7906aaa4aabSotto /*
7916fe57b42Smillert  * Add a new partition.
7926fe57b42Smillert  */
7936fe57b42Smillert void
editor_add(struct disklabel * lp,const char * p)794c0bc1f19Skrw editor_add(struct disklabel *lp, const char *p)
7956fe57b42Smillert {
79696a888c6Smillert 	struct partition *pp;
797ab2017adSkrw 	const struct diskchunk *chunk;
798a83eeb72Skrw 	int partno;
7992fcfb0f5Skrw 	u_int64_t new_offset, new_size;
8009fdcb4d6Skrw 
8012fcfb0f5Skrw 	chunk = free_chunks(lp, -1);
8022fcfb0f5Skrw 	new_size = new_offset = 0;
8032fcfb0f5Skrw 	for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
804b46f7512Skrw 		if (CHUNKSZ(chunk) > new_size) {
805b46f7512Skrw 			new_size = CHUNKSZ(chunk);
8062fcfb0f5Skrw 			new_offset = chunk->start;
8072fcfb0f5Skrw 		}
8082fcfb0f5Skrw 	}
8096fe57b42Smillert 
810fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
8112fcfb0f5Skrw 	if ((lp->d_flags & D_VENDOR) && new_size < lp->d_secpercyl) {
812fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
813fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
814fc1a4cc6Sderaadt 		    stderr);
815fc1a4cc6Sderaadt 		return;
816fc1a4cc6Sderaadt 	}
8178390cf28Smillert #endif
8182fcfb0f5Skrw 	if (new_size == 0) {
8196fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
8206fe57b42Smillert 		    stderr);
8216fe57b42Smillert 		return;
8226fe57b42Smillert 	}
8236fe57b42Smillert 
82496b465e9Skrw 	if ((partno = getpartno(lp, p, "add")) == -1)
8255caa08b2Skrw 		return;
8265caa08b2Skrw 	pp = &lp->d_partitions[partno];
8272fcfb0f5Skrw 	memset(pp, 0, sizeof(*pp));
82896a888c6Smillert 
829caf41f96Skrw 	/*
830caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
831855d4e83Ssobrado 	 * zero'ed to avoid inadvertent overlaps.
832caf41f96Skrw 	 */
833caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
834caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
83596a888c6Smillert 
8361e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
8371e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
83896a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
839c88f83bdSotto 
840c88f83bdSotto 	if (get_offset(lp, partno) == 0 &&
841a3ad4147Skrw 	    get_size(lp, partno) == 0 &&
842a3ad4147Skrw 	    get_fstype(lp, partno) == 0 &&
84334ae4198Skrw 	    get_mp(lp, partno) == 0 &&
844728b9255Skrw 	    set_fragblock(lp, partno) == 0)
84596a888c6Smillert 		return;
846a3ad4147Skrw 
847a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
848da2bd3f5Skrw 	memset(pp, 0, sizeof(*pp));
8496fe57b42Smillert }
8506fe57b42Smillert 
8516fe57b42Smillert /*
852bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
853bd6726faSmillert  */
854bd6726faSmillert void
editor_name(const struct disklabel * lp,const char * p)85541d86e10Skrw editor_name(const struct disklabel *lp, const char *p)
856bd6726faSmillert {
857bd6726faSmillert 	int partno;
858bd6726faSmillert 
85978ff4c86Skrw 	if ((partno = getpartno(lp, p, "name")) == -1)
860bd6726faSmillert 		return;
861bd6726faSmillert 
86234ae4198Skrw 	get_mp(lp, partno);
863bd6726faSmillert }
864bd6726faSmillert 
865bd6726faSmillert /*
8666fe57b42Smillert  * Change an existing partition.
8676fe57b42Smillert  */
8686fe57b42Smillert void
editor_modify(struct disklabel * lp,const char * p)869c0bc1f19Skrw editor_modify(struct disklabel *lp, const char *p)
8706fe57b42Smillert {
87140b226e8Skrw 	struct partition opp, *pp;
872f8ab7229Schl 	int partno;
8736fe57b42Smillert 
87478ff4c86Skrw 	if ((partno = getpartno(lp, p, "modify")) == -1)
87596a888c6Smillert 		return;
87678ff4c86Skrw 
87766df1f0cSkrw 	pp = &lp->d_partitions[partno];
87840b226e8Skrw 	opp = *pp;
87966df1f0cSkrw 
880a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
881a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
882a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
88334ae4198Skrw 	    get_mp(lp, partno) == 0 &&
884728b9255Skrw 	    set_fragblock(lp, partno) == 0)
88596a888c6Smillert 		return;
8866fe57b42Smillert 
887a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
88840b226e8Skrw 	*pp = opp;
8896fe57b42Smillert }
8906fe57b42Smillert 
8916fe57b42Smillert /*
8926fe57b42Smillert  * Delete an existing partition.
8936fe57b42Smillert  */
8946fe57b42Smillert void
editor_delete(struct disklabel * lp,const char * p)895c0bc1f19Skrw editor_delete(struct disklabel *lp, const char *p)
8966fe57b42Smillert {
89766df1f0cSkrw 	struct partition *pp;
898135c90d1Skrw 	int partno;
8996fe57b42Smillert 
90081f2740fSkrw 	if ((partno = getpartno(lp, p, "delete")) == -1)
90196a888c6Smillert 		return;
90281f2740fSkrw 	if (partno == lp->d_npartitions) {
9039fdcb4d6Skrw 		zero_partitions(lp);
904945ae268Smillert 		return;
905945ae268Smillert 	}
906135c90d1Skrw 	pp = &lp->d_partitions[partno];
90766df1f0cSkrw 
9086fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
909135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
91034ae4198Skrw 	free(mountpoints[partno]);
91134ae4198Skrw 	mountpoints[partno] = NULL;
9126fe57b42Smillert }
9136fe57b42Smillert 
9146fe57b42Smillert /*
9156fe57b42Smillert  * Change the size of an existing partition.
9166fe57b42Smillert  */
9176fe57b42Smillert void
editor_change(struct disklabel * lp,const char * p)918c0bc1f19Skrw editor_change(struct disklabel *lp, const char *p)
9196fe57b42Smillert {
9204b9a3bdaSmillert 	struct partition *pp;
92166df1f0cSkrw 	int partno;
9226fe57b42Smillert 
92378ff4c86Skrw 	if ((partno = getpartno(lp, p, "change size")) == -1)
92496a888c6Smillert 		return;
92578ff4c86Skrw 
9264b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
92714192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
92814192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
92978ff4c86Skrw 	    'a' + partno, DL_GETPSIZE(pp), max_partition_size(lp, partno));
9307da73705Skrw 
93159ccf790Skrw 	/* Get new size */
9329fdcb4d6Skrw 	get_size(lp, partno);
9336fe57b42Smillert }
9346fe57b42Smillert 
9356fe57b42Smillert /*
9366fe57b42Smillert  * Sort the partitions based on starting offset.
9376fe57b42Smillert  * This assumes there can be no overlap.
9386fe57b42Smillert  */
9396fe57b42Smillert int
partition_cmp(const void * e1,const void * e2)9408809fabbSderaadt partition_cmp(const void *e1, const void *e2)
9416fe57b42Smillert {
9426fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
9436fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
9441e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
9451e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
9466fe57b42Smillert 
9471e0ad43cSotto 	if (o1 < o2)
948651d5bd9Sotto 		return -1;
9491e0ad43cSotto 	else if (o1 > o2)
950651d5bd9Sotto 		return 1;
951651d5bd9Sotto 	else
952651d5bd9Sotto 		return 0;
9536fe57b42Smillert }
9546fe57b42Smillert 
9556fe57b42Smillert char *
getstring(const char * prompt,const char * helpstring,const char * oval)956b228e876Smiod getstring(const char *prompt, const char *helpstring, const char *oval)
9576fe57b42Smillert {
9586fe57b42Smillert 	static char buf[BUFSIZ];
9596fe57b42Smillert 	int n;
9606fe57b42Smillert 
9616fe57b42Smillert 	buf[0] = '\0';
9626fe57b42Smillert 	do {
9636fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
9646e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
965260513deSmillert 			buf[0] = '\0';
96696a888c6Smillert 			if (feof(stdin)) {
96724c6582eSmillert 				clearerr(stdin);
96896a888c6Smillert 				putchar('\n');
969ac30837aSkrw 				fputs("Command aborted\n", stderr);
970bb12209fSkrw 				return NULL;
97196a888c6Smillert 			}
9726e0becc5Smillert 		}
9736fe57b42Smillert 		n = strlen(buf);
9746fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
9756fe57b42Smillert 			buf[--n] = '\0';
9766fe57b42Smillert 		if (buf[0] == '?')
9776fe57b42Smillert 			puts(helpstring);
9784fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
9794fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
9806fe57b42Smillert 	} while (buf[0] == '?');
9816fe57b42Smillert 
982bb12209fSkrw 	return &buf[0];
9836fe57b42Smillert }
9846fe57b42Smillert 
98578ff4c86Skrw int
getpartno(const struct disklabel * lp,const char * p,const char * action)98696b465e9Skrw getpartno(const struct disklabel *lp, const char *p, const char *action)
98778ff4c86Skrw {
98896b465e9Skrw 	char buf[2] = { '\0', '\0'};
98978ff4c86Skrw 	const char *promptfmt = "partition to %s";
99078ff4c86Skrw 	const char *helpfmt = "Partition must be between 'a' and '%c' "
99181f2740fSkrw 	    "(excluding 'c')%s.\n";
99278ff4c86Skrw 	const struct partition *pp;
99378ff4c86Skrw 	char *help = NULL, *prompt = NULL;
99496b465e9Skrw 	unsigned char maxpart;
99578ff4c86Skrw 	unsigned int partno;
99681f2740fSkrw 	int add, delete, inuse;
99778ff4c86Skrw 
99896b465e9Skrw 	add = strcmp("add", action) == 0;
99981f2740fSkrw 	delete = strcmp("delete", action) == 0;
100096b465e9Skrw 	maxpart = 'a' - 1 + (add ? MAXPARTITIONS : lp->d_npartitions);
100196b465e9Skrw 
100278ff4c86Skrw 	if (p == NULL) {
100378ff4c86Skrw 		if (asprintf(&prompt, promptfmt, action) == -1 ||
100481f2740fSkrw 		    asprintf(&help, helpfmt, maxpart, delete ? ", or '*'" : "")
100581f2740fSkrw 		    == -1) {
100678ff4c86Skrw 			fprintf(stderr, "Unable to build prompt or help\n");
100796b465e9Skrw 			goto done;
100896b465e9Skrw 		}
100996b465e9Skrw 		if (add) {
101096b465e9Skrw 			/* Default to first unused partition. */
101196b465e9Skrw 			for (partno = 0; partno < MAXPARTITIONS; partno++) {
101296b465e9Skrw 				if (partno == RAW_PART)
101396b465e9Skrw 					continue;
101496b465e9Skrw 				pp = &lp->d_partitions[partno];
101596b465e9Skrw 				if (partno >= lp->d_npartitions ||
101696b465e9Skrw 				    DL_GETPSIZE(pp) == 0 ||
101796b465e9Skrw 				    pp->p_fstype == FS_UNUSED) {
101896b465e9Skrw 					buf[0] = 'a' + partno;
101996b465e9Skrw 					p = buf;
102096b465e9Skrw 					break;
102196b465e9Skrw 				}
102296b465e9Skrw 			}
102396b465e9Skrw 		}
102496b465e9Skrw 		p = getstring(prompt, help, p);
102578ff4c86Skrw 		free(prompt);
102678ff4c86Skrw 		free(help);
102778ff4c86Skrw 		if (p == NULL || *p == '\0')
102878ff4c86Skrw 			goto done;
102978ff4c86Skrw 	}
103078ff4c86Skrw 
103181f2740fSkrw 	if (delete && strlen(p) == 1 && *p == '*')
1032bb12209fSkrw 		return lp->d_npartitions;
103381f2740fSkrw 
1034715dd5c0Skrw 	if (strlen(p) > 1 || *p < 'a' || *p > maxpart || *p == 'c') {
103581f2740fSkrw 		fprintf(stderr, helpfmt, maxpart, delete ? ", or '*'" : "");
103678ff4c86Skrw 		goto done;
103778ff4c86Skrw 	}
103878ff4c86Skrw 
103978ff4c86Skrw 	partno = *p - 'a';
104078ff4c86Skrw 	pp = &lp->d_partitions[partno];
104196b465e9Skrw 	inuse = partno < lp->d_npartitions && DL_GETPSIZE(pp) > 0 &&
104296b465e9Skrw 	    pp->p_fstype != FS_UNUSED;
104396b465e9Skrw 
104496b465e9Skrw 	if ((add && !inuse) || (!add && inuse))
1045bb12209fSkrw 		return partno;
104678ff4c86Skrw 
104796b465e9Skrw 	fprintf(stderr, "Partition '%c' is %sin use.\n", *p,
104896b465e9Skrw 	    inuse ? "" : "not ");
104978ff4c86Skrw 
105078ff4c86Skrw  done:
1051bb12209fSkrw 	return -1;
105278ff4c86Skrw }
105378ff4c86Skrw 
10546fe57b42Smillert /*
1055aa3970cdSkrw  * Returns
1056aa3970cdSkrw  * 0 .. CMD_ABORTED - 1	==> valid value
1057aa3970cdSkrw  * CMD_BADVALUE		==> invalid value
1058aa3970cdSkrw  * CMD_ABORTED		==> ^D on input
10596fe57b42Smillert  */
10601e0ad43cSotto u_int64_t
getnumber(const char * prompt,const char * helpstring,u_int32_t oval,u_int32_t maxval)1061c0bc1f19Skrw getnumber(const char *prompt, const char *helpstring, u_int32_t oval,
1062c0bc1f19Skrw     u_int32_t maxval)
10630db7769aSkrw {
10640db7769aSkrw 	char buf[BUFSIZ], *p;
10650db7769aSkrw 	int rslt;
10660db7769aSkrw 	long long rval;
10670db7769aSkrw 	const char *errstr;
10680db7769aSkrw 
10690db7769aSkrw 	rslt = snprintf(buf, sizeof(buf), "%u", oval);
1070515e489cSderaadt 	if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
1071bb12209fSkrw 		return CMD_BADVALUE;
10720db7769aSkrw 
10730db7769aSkrw 	p = getstring(prompt, helpstring, buf);
10740db7769aSkrw 	if (p == NULL)
1075bb12209fSkrw 		return CMD_ABORTED;
10760db7769aSkrw 	if (strlen(p) == 0)
1077bb12209fSkrw 		return oval;
10780db7769aSkrw 
10790db7769aSkrw 	rval = strtonum(p, 0, maxval, &errstr);
10800db7769aSkrw 	if (errstr != NULL) {
10810db7769aSkrw 		printf("%s must be between 0 and %u\n", prompt, maxval);
1082bb12209fSkrw 		return CMD_BADVALUE;
10830db7769aSkrw 	}
10840db7769aSkrw 
1085bb12209fSkrw 	return rval;
10860db7769aSkrw }
10870db7769aSkrw 
10880db7769aSkrw /*
10890db7769aSkrw  * Returns
10900db7769aSkrw  * 0 .. CMD_ABORTED - 1	==> valid value
10910db7769aSkrw  * CMD_BADVALUE		==> invalid value
10920db7769aSkrw  * CMD_ABORTED		==> ^D on input
10930db7769aSkrw  */
10940db7769aSkrw u_int64_t
getuint64(const struct disklabel * lp,char * prompt,char * helpstring,u_int64_t oval,u_int64_t maxval,int * flags)109543ba7787Skrw getuint64(const struct disklabel *lp, char *prompt, char *helpstring,
109640b226e8Skrw     u_int64_t oval, u_int64_t maxval, int *flags)
10976fe57b42Smillert {
10981fec2892Skrw 	char buf[21], *p, operator = '\0';
10991fec2892Skrw 	char *unit = NULL;
11001e0ad43cSotto 	u_int64_t rval = oval;
11011fec2892Skrw 	double d;
11029a4afaafSkrw 	int rslt;
11036fe57b42Smillert 
11049a4afaafSkrw 	rslt = snprintf(buf, sizeof(buf), "%llu", oval);
1105515e489cSderaadt 	if (rslt < 0 || (unsigned int)rslt >= sizeof(buf))
11069a4afaafSkrw 		goto invalid;
11079a4afaafSkrw 
11089a4afaafSkrw 	p = getstring(prompt, helpstring, buf);
11099a4afaafSkrw 	if (p == NULL)
1110bb12209fSkrw 		return CMD_ABORTED;
11111fec2892Skrw 	else if (p[0] == '\0')
11121fec2892Skrw 		rval = oval;
11131fec2892Skrw 	else if (p[0] == '*' && p[1] == '\0')
11146fe57b42Smillert 		rval = maxval;
11151fec2892Skrw 	else {
11161fec2892Skrw 		if (*p == '+' || *p == '-')
11171fec2892Skrw 			operator = *p++;
11181fec2892Skrw 		if (parse_sizespec(p, &d, &unit) == -1)
11191fec2892Skrw 			goto invalid;
11201fec2892Skrw 		if (unit == NULL)
11211fec2892Skrw 			rval = d;
11221fec2892Skrw 		else if (flags != NULL && (*flags & DO_CONVERSIONS) == 0)
11231fec2892Skrw 			goto invalid;
11241fec2892Skrw 		else {
11251fec2892Skrw 			switch (tolower((unsigned char)*unit)) {
11266fe57b42Smillert 			case 'b':
11271fec2892Skrw 				rval = d / lp->d_secsize;
11286fe57b42Smillert 				break;
11291fec2892Skrw 			case 'c':
11301fec2892Skrw 				rval = d * lp->d_secpercyl;
11311a51a1eeSmillert 				break;
113214cc915fSmillert 			case '%':
11331fec2892Skrw 				rval = DL_GETDSIZE(lp) * (d / 100.0);
113414cc915fSmillert 				break;
113514cc915fSmillert 			case '&':
11361fec2892Skrw 				rval = maxval * (d / 100.0);
11371fec2892Skrw 				break;
11381fec2892Skrw 			default:
11391fec2892Skrw 				if (apply_unit(d, *unit, &rval) == -1)
11401fec2892Skrw 					goto invalid;
11411fec2892Skrw 				rval = DL_BLKTOSEC(lp, rval);
114214cc915fSmillert 				break;
11436fe57b42Smillert 			}
114496a888c6Smillert 		}
11456fe57b42Smillert 
1146e15dcdb4Skrw 		/* Range check then apply [+-] operator */
1147e15dcdb4Skrw 		if (operator == '+') {
1148aa3970cdSkrw 			if (CMD_ABORTED - oval > rval)
11496fe57b42Smillert 				rval += oval;
1150e15dcdb4Skrw 			else {
1151ac30837aSkrw 				goto invalid;
1152e15dcdb4Skrw 			}
1153e15dcdb4Skrw 		} else if (operator == '-') {
1154e15dcdb4Skrw 			if (oval >= rval)
11556fe57b42Smillert 				rval = oval - rval;
1156e15dcdb4Skrw 			else {
1157ac30837aSkrw 				goto invalid;
1158e15dcdb4Skrw 			}
1159e15dcdb4Skrw 		}
11606fe57b42Smillert 	}
116140b226e8Skrw 
116240b226e8Skrw 	if (flags != NULL) {
11631fec2892Skrw 		if (unit != NULL)
116440b226e8Skrw 			*flags |= DO_ROUNDING;
1165fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
116640b226e8Skrw 		if (lp->d_flags & D_VENDOR)
116740b226e8Skrw 			*flags |= DO_ROUNDING;
1168dbffb156Smillert #endif
11696fe57b42Smillert 	}
1170bb12209fSkrw 	return rval;
1171ac30837aSkrw 
1172ac30837aSkrw invalid:
1173ac30837aSkrw 	fputs("Invalid entry\n", stderr);
1174bb12209fSkrw 	return CMD_BADVALUE;
11756fe57b42Smillert }
11766fe57b42Smillert 
11776fe57b42Smillert /*
11781f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
11791f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
11806fe57b42Smillert  */
11816fe57b42Smillert int
has_overlap(struct disklabel * lp)11821f0f871dSkrw has_overlap(struct disklabel *lp)
11836fe57b42Smillert {
118443ba7787Skrw 	const struct partition **spp;
11850f1cd5a2Skrw 	int i, p1, p2;
11860f1cd5a2Skrw 	char *line = NULL;
11870f1cd5a2Skrw 	size_t linesize = 0;
11880f1cd5a2Skrw 	ssize_t linelen;
11896fe57b42Smillert 
11900f1cd5a2Skrw 	for (;;) {
1191411a261cSkrw 		spp = sort_partitions(lp, -1);
11920f1cd5a2Skrw 		for (i = 0; spp[i+1] != NULL; i++) {
1193430e1380Skrw 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) >
11940f1cd5a2Skrw 			    DL_GETPOFFSET(spp[i+1]))
11950f1cd5a2Skrw 				break;
1196616cd1c4Smillert 		}
11970f1cd5a2Skrw 		if (spp[i+1] == NULL) {
11980f1cd5a2Skrw 			free(line);
1199bb12209fSkrw 			return 0;
12006fe57b42Smillert 		}
12016fe57b42Smillert 
12020f1cd5a2Skrw 		p1 = 'a' + (spp[i] - lp->d_partitions);
12030f1cd5a2Skrw 		p2 = 'a' + (spp[i+1] - lp->d_partitions);
12040f1cd5a2Skrw 		printf("\nError, partitions %c and %c overlap:\n", p1, p2);
12050f1cd5a2Skrw 		printf("#    %16.16s %16.16s  fstype [fsize bsize    cpg]\n",
12060f1cd5a2Skrw 		    "size", "offset");
12070f1cd5a2Skrw 		display_partition(stdout, lp, p1 - 'a', 0);
12080f1cd5a2Skrw 		display_partition(stdout, lp, p2 - 'a', 0);
12090f1cd5a2Skrw 
12100f1cd5a2Skrw 		for (;;) {
12110f1cd5a2Skrw 			printf("Disable which one? (%c %c) ", p1, p2);
12120f1cd5a2Skrw 			linelen = getline(&line, &linesize, stdin);
12130f1cd5a2Skrw 			if (linelen == -1)
12140f1cd5a2Skrw 				goto done;
12150f1cd5a2Skrw 			if (linelen == 2 && (line[0] == p1 || line[0] == p2))
12160f1cd5a2Skrw 				break;
12170f1cd5a2Skrw 		}
12180f1cd5a2Skrw 		lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED;
12190f1cd5a2Skrw 	}
12200f1cd5a2Skrw 
12210f1cd5a2Skrw done:
12220f1cd5a2Skrw 	putchar('\n');
12230f1cd5a2Skrw 	free(line);
1224bb12209fSkrw 	return 1;
12250f1cd5a2Skrw }
12260f1cd5a2Skrw 
12276fe57b42Smillert void
edit_packname(struct disklabel * lp)12281cc333d2Skrw edit_packname(struct disklabel *lp)
12296fe57b42Smillert {
12306fe57b42Smillert 	char *p;
123196a888c6Smillert 	struct disklabel oldlabel = *lp;
12326fe57b42Smillert 
12331cc333d2Skrw 	printf("Changing label description for %s:\n", specname);
12340f820bbbSmillert 
12356fe57b42Smillert 	/* pack/label id */
1236c33fcabaSmillert 	p = getstring("label name",
12376fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
12386fe57b42Smillert 	    lp->d_packname);
123996a888c6Smillert 	if (p == NULL) {
124096a888c6Smillert 		*lp = oldlabel;		/* undo damage */
124196a888c6Smillert 		return;
124296a888c6Smillert 	}
12434fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
12446fe57b42Smillert }
1245a7e61405Smillert 
124643ba7787Skrw const struct partition **
sort_partitions(const struct disklabel * lp,int ignore)124743ba7787Skrw sort_partitions(const struct disklabel *lp, int ignore)
1248a7e61405Smillert {
124943ba7787Skrw 	const static struct partition *spp[MAXPARTITIONS+2];
12500fbd3c97Skrw 	int i, npartitions;
1251a7e61405Smillert 
1252d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1253d18c2a43Skrw 
1254a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1255411a261cSkrw 		if (i != ignore && lp->d_partitions[i].p_fstype != FS_UNUSED &&
12561e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1257a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1258a7e61405Smillert 	}
1259a7e61405Smillert 
1260a7e61405Smillert 	/*
1261a7e61405Smillert 	 * Sort the partitions based on starting offset.
1262a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1263a7e61405Smillert 	 */
1264a7e61405Smillert 	if (npartitions > 1)
12650f1cd5a2Skrw 		if (mergesort((void *)spp, npartitions, sizeof(spp[0]),
1266a7e61405Smillert 		    partition_cmp))
1267a7e61405Smillert 			err(4, "failed to sort partition table");
1268a7e61405Smillert 
1269bb12209fSkrw 	return spp;
1270a7e61405Smillert }
12710f820bbbSmillert 
12720f820bbbSmillert /*
127396a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
127496a888c6Smillert  * from the user.
127596a888c6Smillert  */
127696a888c6Smillert void
set_bounds(struct disklabel * lp)12779fdcb4d6Skrw set_bounds(struct disklabel *lp)
127896a888c6Smillert {
12791e0ad43cSotto 	u_int64_t ui, start_temp;
128096a888c6Smillert 
128196a888c6Smillert 	/* Starting sector */
1282f1bc1b27Skrw 	for (;;) {
1283117239d3Skrw 		ui = getuint64(lp, "Starting sector",
128496a888c6Smillert 		    "The start of the OpenBSD portion of the disk.",
128540b226e8Skrw 		    starting_sector, DL_GETDSIZE(lp), NULL);
1286aa3970cdSkrw 		if (ui == CMD_ABORTED)
128796a888c6Smillert 			return;
1288aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1289f1bc1b27Skrw 			;	/* Try again. */
1290f1bc1b27Skrw 		else if (ui >= DL_GETDSIZE(lp))
1291f1bc1b27Skrw 			fprintf(stderr, "starting sector must be < %llu\n",
1292f1bc1b27Skrw 			    DL_GETDSIZE(lp));
1293f1bc1b27Skrw 		else
1294f1bc1b27Skrw 			break;
1295f1bc1b27Skrw 	}
129696a888c6Smillert 	start_temp = ui;
129796a888c6Smillert 
12984793b14cSmillert 	/* Size */
1299f1bc1b27Skrw 	for (;;) {
1300117239d3Skrw 		ui = getuint64(lp, "Size ('*' for entire disk)",
1301f98aebd4Smillert 		    "The size of the OpenBSD portion of the disk ('*' for the "
1302f98aebd4Smillert 		    "entire disk).", ending_sector - starting_sector,
130340b226e8Skrw 		    DL_GETDSIZE(lp) - start_temp, NULL);
1304aa3970cdSkrw 		if (ui == CMD_ABORTED)
130596a888c6Smillert 			return;
1306aa3970cdSkrw 		else if (ui == CMD_BADVALUE)
1307f1bc1b27Skrw 			;	/* Try again. */
1308f1bc1b27Skrw 		else if (ui > DL_GETDSIZE(lp) - start_temp)
1309f1bc1b27Skrw 			fprintf(stderr, "size must be <= %llu\n",
1310f1bc1b27Skrw 			    DL_GETDSIZE(lp) - start_temp);
1311f1bc1b27Skrw 		else
1312f1bc1b27Skrw 			break;
1313f1bc1b27Skrw 	}
13144793b14cSmillert 	ending_sector = start_temp + ui;
131578f0fb17Skrw 	DL_SETBEND(lp, ending_sector);
131696a888c6Smillert 	starting_sector = start_temp;
131778f0fb17Skrw 	DL_SETBSTART(lp, starting_sector);
131896a888c6Smillert }
131996a888c6Smillert 
132096a888c6Smillert /*
13210d63cfbaSjsing  * Allow user to interactively change disklabel UID.
13220d63cfbaSjsing  */
13230d63cfbaSjsing void
set_duid(struct disklabel * lp)132469a6ffbcSjsing set_duid(struct disklabel *lp)
13250d63cfbaSjsing {
13260d63cfbaSjsing 	char *s;
13270d63cfbaSjsing 	int i;
13280d63cfbaSjsing 
1329f6ad9e2dSjsing 	printf("The disklabel UID is currently: "
1330f6ad9e2dSjsing 	    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
1331f6ad9e2dSjsing 	    lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
1332f6ad9e2dSjsing 	    lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
13330d63cfbaSjsing 
13340d63cfbaSjsing 	do {
133569a6ffbcSjsing 		s = getstring("duid", "The disklabel UID, given as a 16 "
13360d63cfbaSjsing 		    "character hexadecimal string.", NULL);
1337ce98d1aeShalex 		if (s == NULL || strlen(s) == 0) {
13380d63cfbaSjsing 			fputs("Command aborted\n", stderr);
13390d63cfbaSjsing 			return;
13400d63cfbaSjsing 		}
134169a6ffbcSjsing 		i = duid_parse(lp, s);
13420d63cfbaSjsing 		if (i != 0)
13430d63cfbaSjsing 			fputs("Invalid UID entered.\n", stderr);
13440d63cfbaSjsing 	} while (i != 0);
13450d63cfbaSjsing }
13460d63cfbaSjsing 
13470d63cfbaSjsing /*
134896a888c6Smillert  * Return a list of the "chunks" of free space available
134996a888c6Smillert  */
1350ab2017adSkrw const struct diskchunk *
free_chunks(const struct disklabel * lp,int partno)135143ba7787Skrw free_chunks(const struct disklabel *lp, int partno)
135296a888c6Smillert {
135343ba7787Skrw 	const struct partition **spp;
135496a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
135599bd27d2Skrw 	u_int64_t start, stop;
135696a888c6Smillert 	int i, numchunks;
135796a888c6Smillert 
13580fbd3c97Skrw 	/* Sort the in-use partitions based on offset */
1359411a261cSkrw 	spp = sort_partitions(lp, partno);
136096a888c6Smillert 
136196a888c6Smillert 	/* If there are no partitions, it's all free. */
13620fbd3c97Skrw 	if (spp[0] == NULL) {
13632d8451b0Smillert 		chunks[0].start = starting_sector;
136496a888c6Smillert 		chunks[0].stop = ending_sector;
136596a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
1366bb12209fSkrw 		return chunks;
136796a888c6Smillert 	}
136896a888c6Smillert 
136996a888c6Smillert 	/* Find chunks of free space */
137096a888c6Smillert 	numchunks = 0;
13710fbd3c97Skrw 	if (DL_GETPOFFSET(spp[0]) > starting_sector) {
13722d8451b0Smillert 		chunks[0].start = starting_sector;
13731e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
137496a888c6Smillert 		numchunks++;
137596a888c6Smillert 	}
13760fbd3c97Skrw 	for (i = 0; spp[i] != NULL; i++) {
137799bd27d2Skrw 		start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
1378aff3f969Sotto 		if (start < starting_sector)
1379aff3f969Sotto 			start = starting_sector;
1380aff3f969Sotto 		else if (start > ending_sector)
1381aff3f969Sotto 			start = ending_sector;
138299bd27d2Skrw 		if (spp[i + 1] != NULL)
138399bd27d2Skrw 			stop = DL_GETPOFFSET(spp[i+1]);
138499bd27d2Skrw 		else
138599bd27d2Skrw 			stop = ending_sector;
1386aff3f969Sotto 		if (stop < starting_sector)
1387aff3f969Sotto 			stop = starting_sector;
1388aff3f969Sotto 		else if (stop > ending_sector)
1389aff3f969Sotto 			stop = ending_sector;
139099bd27d2Skrw 		if (start < stop) {
139199bd27d2Skrw 			chunks[numchunks].start = start;
139299bd27d2Skrw 			chunks[numchunks].stop = stop;
139396a888c6Smillert 			numchunks++;
139496a888c6Smillert 		}
139596a888c6Smillert 	}
139696a888c6Smillert 
139796a888c6Smillert 	/* Terminate and return */
139896a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
1399bb12209fSkrw 	return chunks;
140096a888c6Smillert }
14014793b14cSmillert 
14024793b14cSmillert void
find_bounds(const struct disklabel * lp)140343ba7787Skrw find_bounds(const struct disklabel *lp)
14044793b14cSmillert {
14056534e983Sderaadt 	starting_sector = DL_GETBSTART(lp);
14066534e983Sderaadt 	ending_sector = DL_GETBEND(lp);
1407b2d4a455Smiod 
14086534e983Sderaadt 	if (ending_sector) {
140934ae4198Skrw 		if (verbose)
141034ae4198Skrw 			printf("Treating sectors %llu-%llu as the OpenBSD"
141134ae4198Skrw 			    " portion of the disk.\nYou can use the 'b'"
141234ae4198Skrw 			    " command to change this.\n\n", starting_sector,
141334ae4198Skrw 			    ending_sector);
14144793b14cSmillert 	}
1415b2d4a455Smiod }
1416c0bdc608Smillert 
1417c0bdc608Smillert /*
1418c0bdc608Smillert  * Calculate free space.
1419c0bdc608Smillert  */
14209fdcb4d6Skrw u_int64_t
editor_countfree(const struct disklabel * lp)142143ba7787Skrw editor_countfree(const struct disklabel *lp)
1422c0bdc608Smillert {
142343ba7787Skrw 	const struct diskchunk *chunk;
14249fdcb4d6Skrw 	u_int64_t freesectors = 0;
1425c0bdc608Smillert 
1426a83eeb72Skrw 	chunk = free_chunks(lp, -1);
1427509930fbSotto 
1428a83eeb72Skrw 	for (; chunk->start != 0 || chunk->stop != 0; chunk++)
1429b46f7512Skrw 		freesectors += CHUNKSZ(chunk);
14309fdcb4d6Skrw 
1431bb12209fSkrw 	return freesectors;
1432c0bdc608Smillert }
1433617e6e4aSmillert 
1434617e6e4aSmillert void
editor_help(void)14354d812bb6Slum editor_help(void)
1436617e6e4aSmillert {
1437617e6e4aSmillert 	puts("Available commands:");
1438617e6e4aSmillert 	puts(
14394d812bb6Slum " ? | h    - show help                 n [part] - set mount point\n"
144049159a67Skrw " A        - auto partition all space  p [unit] - print partitions\n"
144149159a67Skrw " a [part] - add partition             q        - quit & save changes\n"
14424659aa0dSotto " b        - set OpenBSD boundaries    R [part] - resize auto allocated partition\n"
144349159a67Skrw " c [part] - change partition size     r        - display free space\n"
14446aaa4aabSotto " D        - reset label to default    s [path] - save label to file\n"
14456aaa4aabSotto " d [part] - delete partition          U        - undo all changes\n"
14461cc333d2Skrw " e        - edit label description    u        - undo last change\n"
1447ba275c17Skrw " i        - modify disklabel UID      w        - write label to disk\n"
1448953cd4efSkrw " l [unit] - print disk label header   x        - exit & lose changes\n"
1449953cd4efSkrw " M        - disklabel(8) man page     z        - delete all partitions\n"
1450953cd4efSkrw " m [part] - modify partition\n"
1451c4884206Skrw "\n"
1452c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n"
1453e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n"
1454e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n"
1455c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary.");
14564d812bb6Slum 
1457617e6e4aSmillert }
1458bd6726faSmillert 
14594f3bbbf0Skrw void
mpcopy(char ** to,char ** from)14608809fabbSderaadt mpcopy(char **to, char **from)
1461bd6726faSmillert {
1462bd6726faSmillert 	int i;
1463bd6726faSmillert 
1464bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1465bd6726faSmillert 		free(to[i]);
1466bd6726faSmillert 		to[i] = NULL;
1467408ab9bcSkrw 		if (from[i] != NULL) {
1468408ab9bcSkrw 			to[i] = strdup(from[i]);
1469408ab9bcSkrw 			if (to[i] == NULL)
1470b7cc13deSkrw 				err(1, NULL);
1471bd6726faSmillert 		}
1472bd6726faSmillert 	}
1473bd6726faSmillert }
1474bd6726faSmillert 
1475bd6726faSmillert int
mpequal(char ** mp1,char ** mp2)14768809fabbSderaadt mpequal(char **mp1, char **mp2)
1477bd6726faSmillert {
1478bd6726faSmillert 	int i;
1479bd6726faSmillert 
1480bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1481bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1482bd6726faSmillert 			continue;
1483bd6726faSmillert 
1484bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1485bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1486bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1487bb12209fSkrw 			return 0;
1488bd6726faSmillert 	}
1489bb12209fSkrw 	return 1;
1490bd6726faSmillert }
1491bd6726faSmillert 
149293160b9bSkrw void
mpsave(const struct disklabel * lp)149343ba7787Skrw mpsave(const struct disklabel *lp)
1494bd6726faSmillert {
1495d8b446ceSderaadt 	int i, j;
1496b9fc9a72Sderaadt 	char bdev[PATH_MAX], *p;
14973f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1498bd6726faSmillert 	FILE *fp;
1499fe01da94Skrw 	u_int8_t fstype;
1500bd6726faSmillert 
150193160b9bSkrw 	if (!fstabfile)
150293160b9bSkrw 		return;
150393160b9bSkrw 
15043f843443Smillert 	memset(&mi, 0, sizeof(mi));
15053f843443Smillert 
1506d8b446ceSderaadt 	for (i = 0; i < MAXPARTITIONS; i++) {
1507fe01da94Skrw 		fstype = lp->d_partitions[i].p_fstype;
1508fe01da94Skrw 		if (mountpoints[i] != NULL || fstype == FS_SWAP) {
150934ae4198Skrw 			mi[i].mountpoint = mountpoints[i];
15103f843443Smillert 			mi[i].partno = i;
1511bd6726faSmillert 		}
1512bd6726faSmillert 	}
1513bd6726faSmillert 
151434ae4198Skrw 	/* Convert specname to bdev */
1515d6d80bb0Skrw 	if (uidflag) {
1516d6d80bb0Skrw 		snprintf(bdev, sizeof(bdev),
1517d6d80bb0Skrw 		    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
1518d6d80bb0Skrw 		    lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3],
1519d6d80bb0Skrw 		    lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7],
1520d6d80bb0Skrw 		    specname[strlen(specname)-1]);
1521d6d80bb0Skrw 	} else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 &&
152234ae4198Skrw 	    specname[sizeof(_PATH_DEV) - 1] == 'r') {
1523bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
152434ae4198Skrw 		    &specname[sizeof(_PATH_DEV)]);
1525bd6726faSmillert 	} else {
152634ae4198Skrw 		if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r')
152793160b9bSkrw 			return;
1528bd6726faSmillert 		*p = '\0';
152934ae4198Skrw 		snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1);
1530bd6726faSmillert 		*p = 'r';
1531bd6726faSmillert 	}
1532bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1533bd6726faSmillert 
15343f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
15353f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
15363f843443Smillert 
1537d71533c9Stedu 	if ((fp = fopen(fstabfile, "w"))) {
1538fe01da94Skrw 		for (i = 0; i < MAXPARTITIONS; i++) {
15395fea0b85Smillert 			j =  mi[i].partno;
1540fe01da94Skrw 			fstype = lp->d_partitions[j].p_fstype;
15414536786eSkrw 			if (fstype == FS_RAID)
15424536786eSkrw 				continue;
1543fe01da94Skrw 			if (fstype == FS_SWAP) {
1544fe01da94Skrw 				fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j);
1545fe01da94Skrw 			} else if (mi[i].mountpoint) {
1546fe01da94Skrw 				fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev,
1547fe01da94Skrw 				    'a' + j, mi[i].mountpoint,
1548fe01da94Skrw 				    fstypesnames[fstype], j == 0 ? 1 : 2);
1549fe01da94Skrw 			}
1550bd6726faSmillert 		}
1551bd6726faSmillert 		fclose(fp);
155293160b9bSkrw 	}
1553bd6726faSmillert }
155424a2c1a4Smillert 
1555408ab9bcSkrw void
mpfree(char ** mp,int action)1556e46ff49bSkrw mpfree(char **mp, int action)
1557408ab9bcSkrw {
1558408ab9bcSkrw 	int part;
1559408ab9bcSkrw 
1560408ab9bcSkrw 	if (mp == NULL)
1561408ab9bcSkrw 		return;
1562408ab9bcSkrw 
1563e46ff49bSkrw 	for (part = 0; part < MAXPARTITIONS; part++) {
1564408ab9bcSkrw 		free(mp[part]);
1565e46ff49bSkrw 		mp[part] = NULL;
1566e46ff49bSkrw 	}
1567408ab9bcSkrw 
1568e46ff49bSkrw 	if (action == DISCARD) {
1569408ab9bcSkrw 		free(mp);
1570e46ff49bSkrw 		mp = NULL;
1571e46ff49bSkrw 	}
1572408ab9bcSkrw }
1573408ab9bcSkrw 
157424a2c1a4Smillert int
get_offset(struct disklabel * lp,int partno)1575604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
157624a2c1a4Smillert {
157740b226e8Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
157840b226e8Skrw 	u_int64_t ui, offsetalign;
157940b226e8Skrw 	int flags;
158024a2c1a4Smillert 
158140b226e8Skrw 	flags = DO_CONVERSIONS;
1582117239d3Skrw 	ui = getuint64(lp, "offset",
15831e0ad43cSotto 	    "Starting sector for this partition.",
15841e0ad43cSotto 	    DL_GETPOFFSET(pp),
158540b226e8Skrw 	    DL_GETPOFFSET(pp), &flags);
1586e9ff19beSkrw 
158740b226e8Skrw 	if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
1588bb12209fSkrw 		return 1;
1589fc1a4cc6Sderaadt #ifdef SUN_AAT0
159040b226e8Skrw 	if (partno == 0 && ui != 0) {
159149bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
159240f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
1593bb12209fSkrw 		return 1;
159424a2c1a4Smillert 	}
159540b226e8Skrw #endif
159640b226e8Skrw 	opp = *pp;
159740b226e8Skrw 	DL_SETPOFFSET(pp, ui);
159840b226e8Skrw 	offsetalign = 1;
159940b226e8Skrw 	if ((flags & DO_ROUNDING) != 0 && pp->p_fstype == FS_BSDFFS)
160040b226e8Skrw 		offsetalign = lp->d_secpercyl;
160140b226e8Skrw 
160240b226e8Skrw 	if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP) == 1) {
160340b226e8Skrw 		*pp = opp;
1604bb12209fSkrw 		return 1;
160515c15d8aSkrw 	}
1606e9ff19beSkrw 
1607bb12209fSkrw 	return 0;
160815c15d8aSkrw }
160924a2c1a4Smillert 
161024a2c1a4Smillert int
get_size(struct disklabel * lp,int partno)16119fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
161224a2c1a4Smillert {
161340b226e8Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
161440b226e8Skrw 	u_int64_t maxsize, ui, sizealign;
161540b226e8Skrw 	int flags;
161614192793Skrw 
161714192793Skrw 	maxsize = max_partition_size(lp, partno);
161840b226e8Skrw 	flags = DO_CONVERSIONS;
1619117239d3Skrw 	ui = getuint64(lp, "size", "Size of the partition. "
16207da73705Skrw 	    "You may also say +/- amount for a relative change.",
162140b226e8Skrw 	    DL_GETPSIZE(pp), maxsize, &flags);
1622e9ff19beSkrw 
162340b226e8Skrw 	if (ui == CMD_ABORTED || ui == CMD_BADVALUE)
1624bb12209fSkrw 		return 1;
162540b226e8Skrw 
162640b226e8Skrw 	opp = *pp;
162759ccf790Skrw 	DL_SETPSIZE(pp, ui);
162840b226e8Skrw 	sizealign = 1;
162940b226e8Skrw 	if ((flags & DO_ROUNDING) != 0 && (pp->p_fstype == FS_SWAP ||
163040b226e8Skrw 	    pp->p_fstype == FS_BSDFFS))
163140b226e8Skrw 		sizealign = lp->d_secpercyl;
163240b226e8Skrw 
163340b226e8Skrw 	if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP) == 1) {
163440b226e8Skrw 		*pp = opp;
1635bb12209fSkrw 		return 1;
163624a2c1a4Smillert 	}
1637e9ff19beSkrw 
1638bb12209fSkrw 	return 0;
1639e9ff19beSkrw }
164024a2c1a4Smillert 
164124a2c1a4Smillert int
set_fragblock(struct disklabel * lp,int partno)1642728b9255Skrw set_fragblock(struct disklabel *lp, int partno)
1643a95dd767Sotto {
1644728b9255Skrw 	struct partition opp, *pp = &lp->d_partitions[partno];
1645728b9255Skrw 	u_int64_t bytes, offsetalign, sizealign;
1646728b9255Skrw 	u_int32_t frag, fsize;
1647a95dd767Sotto 
16484aa85578Skrw 	if (pp->p_fstype != FS_BSDFFS)
1649bb12209fSkrw 		return 0;
16504aa85578Skrw 
16514aa85578Skrw 	if (pp->p_cpg == 0)
16524aa85578Skrw 		pp->p_cpg = 1;
16534aa85578Skrw 
1654ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1655ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1656a3ad4147Skrw 	if (fsize == 0) {
1657a3ad4147Skrw 		fsize = 2048;
1658ddfcbf38Sotto 		frag = 8;
1659a3ad4147Skrw 		bytes = DL_GETPSIZE(pp) * lp->d_secsize;
1660a3ad4147Skrw 		if (bytes > 128ULL * 1024 * 1024 * 1024)
1661a3ad4147Skrw 			fsize *= 2;
1662a3ad4147Skrw 		if (bytes > 512ULL * 1024 * 1024 * 1024)
1663a3ad4147Skrw 			fsize *= 2;
1664a3ad4147Skrw 		if (fsize < lp->d_secsize)
1665a3ad4147Skrw 			fsize = lp->d_secsize;
1666a3ad4147Skrw 		if (fsize > MAXBSIZE / frag)
1667a3ad4147Skrw 			fsize = MAXBSIZE / frag;
1668a3ad4147Skrw 		pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag);
1669a3ad4147Skrw 	}
1670953cd4efSkrw #ifdef SUN_CYLCHECK
1671bb12209fSkrw 	return 0;
1672953cd4efSkrw #endif
167340b226e8Skrw 	opp = *pp;
167440b226e8Skrw 	sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) *
167540b226e8Skrw 	    DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize;
167640b226e8Skrw 	offsetalign = 1;
167740b226e8Skrw 	if (DL_GETPOFFSET(pp) != starting_sector)
167840b226e8Skrw 		offsetalign = sizealign;
167940b226e8Skrw 
1680922b28b8Skrw 	if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP |
1681922b28b8Skrw 	    ROUND_SIZE_DOWN | ROUND_SIZE_OVERLAP) == 1) {
168240b226e8Skrw 		*pp = opp;
1683bb12209fSkrw 		return 1;
168440b226e8Skrw 	}
168540b226e8Skrw 
1686bb12209fSkrw 	return 0;
168724a2c1a4Smillert }
168824a2c1a4Smillert 
168924a2c1a4Smillert int
get_fstype(struct disklabel * lp,int partno)16908809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
169124a2c1a4Smillert {
169224a2c1a4Smillert 	char *p;
16931e0ad43cSotto 	u_int64_t ui;
169424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
169524a2c1a4Smillert 
169624a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
1697c33fcabaSmillert 		p = getstring("FS type",
169824a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
169924a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
170024a2c1a4Smillert 		if (p == NULL) {
1701bb12209fSkrw 			return 1;
170224a2c1a4Smillert 		}
170324a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
170424a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
170524a2c1a4Smillert 				pp->p_fstype = ui;
170624a2c1a4Smillert 				break;
170724a2c1a4Smillert 			}
170824a2c1a4Smillert 		}
170924a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
1710430e1380Skrw 			printf("Unrecognized filesystem type '%s', treating "
1711430e1380Skrw 			    "as 'unknown'\n", p);
171224a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
171324a2c1a4Smillert 		}
171424a2c1a4Smillert 	} else {
171524a2c1a4Smillert 		for (;;) {
17160db7769aSkrw 			ui = getnumber("FS type (decimal)",
1717430e1380Skrw 			    "Filesystem type as a decimal number; usually 7 "
1718430e1380Skrw 			    "(4.2BSD) or 1 (swap).",
17190db7769aSkrw 			    pp->p_fstype, UINT8_MAX);
1720aa3970cdSkrw 			if (ui == CMD_ABORTED)
1721bb12209fSkrw 				return 1;
1722aa3970cdSkrw 			else if (ui == CMD_BADVALUE)
1723ac30837aSkrw 				;	/* Try again. */
172424a2c1a4Smillert 			else
172524a2c1a4Smillert 				break;
172624a2c1a4Smillert 		}
172724a2c1a4Smillert 		pp->p_fstype = ui;
172824a2c1a4Smillert 	}
1729bb12209fSkrw 	return 0;
173024a2c1a4Smillert }
173124a2c1a4Smillert 
173224a2c1a4Smillert int
get_mp(const struct disklabel * lp,int partno)173341d86e10Skrw get_mp(const struct disklabel *lp, int partno)
173424a2c1a4Smillert {
173541d86e10Skrw 	const struct partition *pp = &lp->d_partitions[partno];
1736ec9fde5fSkrw 	char *p;
1737ec9fde5fSkrw 	int i;
173824a2c1a4Smillert 
1739b308f3d4Skrw 	if (fstabfile == NULL ||
1740b308f3d4Skrw 	    pp->p_fstype == FS_UNUSED ||
1741b308f3d4Skrw 	    pp->p_fstype == FS_SWAP ||
1742b308f3d4Skrw 	    pp->p_fstype == FS_BOOT ||
1743b308f3d4Skrw 	    pp->p_fstype == FS_OTHER ||
1744b308f3d4Skrw 	    pp->p_fstype == FS_RAID) {
1745b308f3d4Skrw 		/* No fstabfile, no names. Not all fstypes can be named */
1746b308f3d4Skrw 		return 0;
1747b308f3d4Skrw 	}
1748b308f3d4Skrw 
1749ddaff619Smillert 	for (;;) {
1750c33fcabaSmillert 		p = getstring("mount point",
175124a2c1a4Smillert 		    "Where to mount this filesystem (ie: / /var /usr)",
175234ae4198Skrw 		    mountpoints[partno] ? mountpoints[partno] : "none");
1753ac30837aSkrw 		if (p == NULL)
1754bb12209fSkrw 			return 1;
1755ddaff619Smillert 		if (strcasecmp(p, "none") == 0) {
175634ae4198Skrw 			free(mountpoints[partno]);
175734ae4198Skrw 			mountpoints[partno] = NULL;
1758ddaff619Smillert 			break;
1759ddaff619Smillert 		}
1760ec9fde5fSkrw 		for (i = 0; i < MAXPARTITIONS; i++)
176193160b9bSkrw 			if (mountpoints[i] != NULL && i != partno &&
1762ec9fde5fSkrw 			    strcmp(p, mountpoints[i]) == 0)
1763ec9fde5fSkrw 				break;
1764ec9fde5fSkrw 		if (i < MAXPARTITIONS) {
176593160b9bSkrw 			fprintf(stderr, "'%c' already being mounted at "
176693160b9bSkrw 			    "'%s'\n", 'a'+i, p);
1767ec9fde5fSkrw 			break;
1768ec9fde5fSkrw 		}
1769ddaff619Smillert 		if (*p == '/') {
1770ddaff619Smillert 			/* XXX - might as well realloc */
177134ae4198Skrw 			free(mountpoints[partno]);
177234ae4198Skrw 			if ((mountpoints[partno] = strdup(p)) == NULL)
1773b7cc13deSkrw 				err(1, NULL);
1774ddaff619Smillert 			break;
1775ddaff619Smillert 		}
1776ddaff619Smillert 		fputs("Mount points must start with '/'\n", stderr);
177724a2c1a4Smillert 	}
1778b308f3d4Skrw 
1779bb12209fSkrw 	return 0;
178024a2c1a4Smillert }
17813f843443Smillert 
17823f843443Smillert int
micmp(const void * a1,const void * a2)17838809fabbSderaadt micmp(const void *a1, const void *a2)
17843f843443Smillert {
17853f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
17863f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
17873f843443Smillert 
17883f843443Smillert 	/* We want all the NULLs at the end... */
17893f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
1790bb12209fSkrw 		return 0;
17913f843443Smillert 	else if (mi1->mountpoint == NULL)
1792bb12209fSkrw 		return 1;
17933f843443Smillert 	else if (mi2->mountpoint == NULL)
1794bb12209fSkrw 		return -1;
17953f843443Smillert 	else
1796bb12209fSkrw 		return strcmp(mi1->mountpoint, mi2->mountpoint);
17973f843443Smillert }
1798c33fcabaSmillert 
1799c33fcabaSmillert void
zero_partitions(struct disklabel * lp)18009fdcb4d6Skrw zero_partitions(struct disklabel *lp)
18019afbe9eeSmillert {
1802e46ff49bSkrw 	memset(lp->d_partitions, 0, sizeof(lp->d_partitions));
180334af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
1804e46ff49bSkrw 
1805e46ff49bSkrw 	mpfree(mountpoints, KEEP);
18069afbe9eeSmillert }
180714192793Skrw 
180814192793Skrw u_int64_t
max_partition_size(const struct disklabel * lp,int partno)180943ba7787Skrw max_partition_size(const struct disklabel *lp, int partno)
181014192793Skrw {
1811ab2017adSkrw 	const struct diskchunk *chunk;
181244ffe03bSotto 	u_int64_t maxsize = 0, offset;
181314192793Skrw 
1814411a261cSkrw 	chunk = free_chunks(lp, partno);
181514192793Skrw 
1816411a261cSkrw 	offset = DL_GETPOFFSET(&lp->d_partitions[partno]);
1817411a261cSkrw 	for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
1818411a261cSkrw 		if (offset < chunk->start || offset >= chunk->stop)
181914192793Skrw 			continue;
1820411a261cSkrw 		maxsize = chunk->stop - offset;
182114192793Skrw 		break;
182214192793Skrw 	}
1823bb12209fSkrw 	return maxsize;
182414192793Skrw }
1825aff3f969Sotto 
1826aff3f969Sotto void
psize(u_int64_t sz,char unit,const struct disklabel * lp)182743ba7787Skrw psize(u_int64_t sz, char unit, const struct disklabel *lp)
1828aff3f969Sotto {
1829aff3f969Sotto 	double d = scale(sz, unit, lp);
1830aff3f969Sotto 	if (d < 0)
1831aff3f969Sotto 		printf("%llu", sz);
1832aff3f969Sotto 	else
1833aff3f969Sotto 		printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit);
1834aff3f969Sotto }
1835aff3f969Sotto 
1836aff3f969Sotto void
display_edit(const struct disklabel * lp,char unit)183743ba7787Skrw display_edit(const struct disklabel *lp, char unit)
1838aff3f969Sotto {
18397ad973c1Skrw 	u_int64_t fr;
1840aff3f969Sotto 	int i;
1841aff3f969Sotto 
18427ad973c1Skrw 	fr = editor_countfree(lp);
1843352d199bSkrw 	unit = canonical_unit(lp, unit);
1844aff3f969Sotto 
1845aff3f969Sotto 	printf("OpenBSD area: ");
184659882f1dSkrw 	psize(starting_sector, 0, lp);
1847aff3f969Sotto 	printf("-");
184859882f1dSkrw 	psize(ending_sector, 0, lp);
1849aff3f969Sotto 	printf("; size: ");
1850aff3f969Sotto 	psize(ending_sector - starting_sector, unit, lp);
1851aff3f969Sotto 	printf("; free: ");
1852aff3f969Sotto 	psize(fr, unit, lp);
1853aff3f969Sotto 
1854aff3f969Sotto 	printf("\n#    %16.16s %16.16s  fstype [fsize bsize   cpg]\n",
1855aff3f969Sotto 	    "size", "offset");
1856aff3f969Sotto 	for (i = 0; i < lp->d_npartitions; i++)
185734ae4198Skrw 		display_partition(stdout, lp, i, unit);
1858aff3f969Sotto }
1859a2c1f847Shenning 
1860a2c1f847Shenning void
parse_autotable(char * filename)1861a2c1f847Shenning parse_autotable(char *filename)
1862a2c1f847Shenning {
1863a2c1f847Shenning 	FILE	*cfile;
18645f012d92Snaddy 	size_t	 linesize = 0;
18655f012d92Snaddy 	char	*line = NULL, *buf, *t;
1866a2c1f847Shenning 	uint	 idx = 0, pctsum = 0;
1867a2c1f847Shenning 	struct space_allocation *sa;
1868a2c1f847Shenning 
1869bc9d58e0Skrw 	if (strcmp(filename, "-") == 0)
1870bc9d58e0Skrw 		cfile = stdin;
1871bc9d58e0Skrw 	else if ((cfile = fopen(filename, "r")) == NULL)
1872a2c1f847Shenning 		err(1, "%s", filename);
1873a2c1f847Shenning 	if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL)
1874a2c1f847Shenning 		err(1, NULL);
1875f55524eaSsthen 	alloc_table_nitems = 1;
1876a2c1f847Shenning 
18775f012d92Snaddy 	while (getline(&line, &linesize, cfile) != -1) {
1878a2c1f847Shenning 		if ((alloc_table[0].table = reallocarray(alloc_table[0].table,
1879a2c1f847Shenning 		    idx + 1, sizeof(*sa))) == NULL)
1880a2c1f847Shenning 			err(1, NULL);
1881a2c1f847Shenning 		sa = &(alloc_table[0].table[idx]);
1882ee18520dSotto 		memset(sa, 0, sizeof(*sa));
1883a2c1f847Shenning 		idx++;
1884a2c1f847Shenning 
18855f012d92Snaddy 		buf = line;
188658c7d7acSnaddy 		if ((sa->mp = get_token(&buf)) == NULL ||
18874536786eSkrw 		    (sa->mp[0] != '/' && strcasecmp(sa->mp, "swap") &&
18884536786eSkrw 		    strcasecmp(sa->mp, "raid")))
1889a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
189058c7d7acSnaddy 		if ((t = get_token(&buf)) == NULL ||
1891a2c1f847Shenning 		    parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1)
1892a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
189358c7d7acSnaddy 		if ((t = get_token(&buf)) != NULL &&
1894a2c1f847Shenning 		    parse_pct(t, &sa->rate) == -1)
1895a2c1f847Shenning 			errx(1, "%s: parse error on line %u", filename, idx);
1896a2c1f847Shenning 		if (sa->minsz > sa->maxsz)
1897a2c1f847Shenning 			errx(1, "%s: min size > max size on line %u", filename,
1898a2c1f847Shenning 			    idx);
1899a2c1f847Shenning 		pctsum += sa->rate;
1900a2c1f847Shenning 	}
1901a2c1f847Shenning 	if (pctsum > 100)
1902a2c1f847Shenning 		errx(1, "%s: sum of extra space allocation > 100%%", filename);
1903a2c1f847Shenning 	alloc_table[0].sz = idx;
19045f012d92Snaddy 	free(line);
1905a2c1f847Shenning 	fclose(cfile);
1906a2c1f847Shenning }
1907a2c1f847Shenning 
1908a2c1f847Shenning char *
get_token(char ** s)190958c7d7acSnaddy get_token(char **s)
1910a2c1f847Shenning {
1911a2c1f847Shenning 	char	*p, *r;
1912a2c1f847Shenning 	size_t	 tlen = 0;
1913a2c1f847Shenning 
1914a2c1f847Shenning 	p = *s;
191558c7d7acSnaddy 	while (**s != '\0' && !isspace((u_char)**s)) {
1916a2c1f847Shenning 		(*s)++;
1917a2c1f847Shenning 		tlen++;
1918a2c1f847Shenning 	}
1919a2c1f847Shenning 	if (tlen == 0)
1920bb12209fSkrw 		return NULL;
1921a2c1f847Shenning 
1922a2c1f847Shenning 	/* eat whitespace */
192358c7d7acSnaddy 	while (isspace((u_char)**s))
1924a2c1f847Shenning 		(*s)++;
1925a2c1f847Shenning 
1926104c1c3cSmillert 	if ((r = strndup(p, tlen)) == NULL)
1927a2c1f847Shenning 		err(1, NULL);
1928bb12209fSkrw 	return r;
1929a2c1f847Shenning }
1930a2c1f847Shenning 
1931a2c1f847Shenning int
apply_unit(double val,u_char unit,u_int64_t * n)1932a2c1f847Shenning apply_unit(double val, u_char unit, u_int64_t *n)
1933a2c1f847Shenning {
1934a2c1f847Shenning 	u_int64_t factor = 1;
1935a2c1f847Shenning 
1936a2c1f847Shenning 	switch (tolower(unit)) {
1937a2c1f847Shenning 	case 't':
1938a2c1f847Shenning 		factor *= 1024;
1939a2c1f847Shenning 		/* FALLTHROUGH */
1940a2c1f847Shenning 	case 'g':
1941a2c1f847Shenning 		factor *= 1024;
1942a2c1f847Shenning 		/* FALLTHROUGH */
1943a2c1f847Shenning 	case 'm':
1944a2c1f847Shenning 		factor *= 1024;
1945a2c1f847Shenning 		/* FALLTHROUGH */
1946a2c1f847Shenning 	case 'k':
1947a2c1f847Shenning 		factor *= 1024;
1948a2c1f847Shenning 		break;
1949a2c1f847Shenning 	default:
1950bb12209fSkrw 		return -1;
1951a2c1f847Shenning 	}
1952a2c1f847Shenning 
1953a2c1f847Shenning 	val *= factor / DEV_BSIZE;
1954b4709bb3Srobert 	if (val > (double)ULLONG_MAX)
1955bb12209fSkrw 		return -1;
1956a2c1f847Shenning 	*n = val;
1957bb12209fSkrw 	return 0;
1958a2c1f847Shenning }
1959a2c1f847Shenning 
1960a2c1f847Shenning int
parse_sizespec(const char * buf,double * val,char ** unit)1961a2c1f847Shenning parse_sizespec(const char *buf, double *val, char **unit)
1962a2c1f847Shenning {
19635f6cf98aSkrw 	errno = 0;
1964a2c1f847Shenning 	*val = strtod(buf, unit);
1965b4709bb3Srobert 	if (errno == ERANGE || *val < 0 || *val > (double)ULLONG_MAX)
1966bb12209fSkrw 		return -1;	/* too big/small */
19675f6cf98aSkrw 	if (*val == 0 && *unit == buf)
1968bb12209fSkrw 		return -1;	/* No conversion performed. */
1969a2c1f847Shenning 	if (*unit != NULL && *unit[0] == '\0')
1970a2c1f847Shenning 		*unit = NULL;
1971bb12209fSkrw 	return 0;
1972a2c1f847Shenning }
1973a2c1f847Shenning 
1974a2c1f847Shenning int
parse_sizerange(char * buf,u_int64_t * min,u_int64_t * max)1975a2c1f847Shenning parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max)
1976a2c1f847Shenning {
1977a2c1f847Shenning 	char	*p, *unit1 = NULL, *unit2 = NULL;
1978a2c1f847Shenning 	double	 val1 = 0, val2 = 0;
1979a2c1f847Shenning 
1980bc9d58e0Skrw 	if (strcmp(buf, "*") == 0) {
1981bc9d58e0Skrw 		*min = 0;
1982bc9d58e0Skrw 		*max = UINT64_MAX;
1983bc9d58e0Skrw 		goto done;
1984bc9d58e0Skrw 	}
1985bc9d58e0Skrw 
1986a2c1f847Shenning 	if ((p = strchr(buf, '-')) != NULL) {
1987a2c1f847Shenning 		p[0] = '\0';
1988a2c1f847Shenning 		p++;
1989a2c1f847Shenning 	}
1990a2c1f847Shenning 	*max = 0;
1991a2c1f847Shenning 	if (parse_sizespec(buf, &val1, &unit1) == -1)
1992bb12209fSkrw 		return -1;
1993a2c1f847Shenning 	if (p != NULL && p[0] != '\0') {
1994a2c1f847Shenning 		if (p[0] == '*')
1995583b3ed6Skrw 			*max = UINT64_MAX;
1996a2c1f847Shenning 		else
1997a2c1f847Shenning 			if (parse_sizespec(p, &val2, &unit2) == -1)
1998bb12209fSkrw 				return -1;
1999a2c1f847Shenning 	}
2000a2c1f847Shenning 	if (unit1 == NULL && (unit1 = unit2) == NULL)
2001bb12209fSkrw 		return -1;
2002a2c1f847Shenning 	if (apply_unit(val1, unit1[0], min) == -1)
2003bb12209fSkrw 		return -1;
2004a2c1f847Shenning 	if (val2 > 0) {
2005a2c1f847Shenning 		if (apply_unit(val2, unit2[0], max) == -1)
2006bb12209fSkrw 			return -1;
2007a2c1f847Shenning 	} else
2008a2c1f847Shenning 		if (*max == 0)
2009a2c1f847Shenning 			*max = *min;
2010bc9d58e0Skrw  done:
2011a2c1f847Shenning 	free(buf);
2012bb12209fSkrw 	return 0;
2013a2c1f847Shenning }
2014a2c1f847Shenning 
2015a2c1f847Shenning int
parse_pct(char * buf,int * n)2016a2c1f847Shenning parse_pct(char *buf, int *n)
2017a2c1f847Shenning {
2018a2c1f847Shenning 	const char	*errstr;
2019a2c1f847Shenning 
2020a2c1f847Shenning 	if (buf[strlen(buf) - 1] == '%')
2021a2c1f847Shenning 		buf[strlen(buf) - 1] = '\0';
2022a2c1f847Shenning 	*n = strtonum(buf, 0, 100, &errstr);
2023a2c1f847Shenning 	if (errstr) {
2024a2c1f847Shenning 		warnx("parse percent %s: %s", buf, errstr);
2025bb12209fSkrw 		return -1;
2026a2c1f847Shenning 	}
2027a2c1f847Shenning 	free(buf);
2028bb12209fSkrw 	return 0;
2029a2c1f847Shenning }
203040b226e8Skrw 
203140b226e8Skrw int
alignpartition(struct disklabel * lp,int partno,u_int64_t startalign,u_int64_t stopalign,int flags)203240b226e8Skrw alignpartition(struct disklabel *lp, int partno, u_int64_t startalign,
203340b226e8Skrw     u_int64_t stopalign, int flags)
203440b226e8Skrw {
203540b226e8Skrw 	struct partition *pp = &lp->d_partitions[partno];
2036ab2017adSkrw 	const struct diskchunk *chunk;
203740b226e8Skrw 	u_int64_t start, stop, maxstop;
203840b226e8Skrw 
203940b226e8Skrw 	start = DL_GETPOFFSET(pp);
204040b226e8Skrw 	if ((flags & ROUND_OFFSET_UP) == ROUND_OFFSET_UP)
20417233a2b0Skrw 		start = ROUNDUP(start, startalign);
204240b226e8Skrw 	else if ((flags & ROUND_OFFSET_DOWN) == ROUND_OFFSET_DOWN)
2043dbdb4107Skrw 		start = ROUNDDOWN(start, startalign);
204440b226e8Skrw 
204540b226e8Skrw 	/* Find the chunk that contains 'start'. */
2046411a261cSkrw 	chunk = free_chunks(lp, partno);
2047411a261cSkrw 	for (; chunk->start != 0 || chunk->stop != 0; chunk++) {
2048411a261cSkrw 		if (start >= chunk->start && start < chunk->stop)
204940b226e8Skrw 			break;
205040b226e8Skrw 	}
2051411a261cSkrw 	if (chunk->stop == 0) {
2052aef735d2Skrw 		fprintf(stderr, "'%c' aligned offset %llu lies outside "
2053aef735d2Skrw 		    "the OpenBSD bounds or inside another partition\n",
2054aef735d2Skrw 		    'a' + partno, start);
2055bb12209fSkrw 		return 1;
205640b226e8Skrw 	}
205740b226e8Skrw 
205840b226e8Skrw 	/* Calculate the new 'stop' sector, the sector after the partition. */
2059aef735d2Skrw 	if ((flags & ROUND_SIZE_OVERLAP) == 0)
2060dbdb4107Skrw 		maxstop = ROUNDDOWN(chunk->stop, stopalign);
2061aef735d2Skrw 	else
2062dbdb4107Skrw 		maxstop = ROUNDDOWN(ending_sector, stopalign);
2063aef735d2Skrw 
206440b226e8Skrw 	stop = DL_GETPOFFSET(pp) + DL_GETPSIZE(pp);
206540b226e8Skrw 	if ((flags & ROUND_SIZE_UP) == ROUND_SIZE_UP)
20667233a2b0Skrw 		stop = ROUNDUP(stop, stopalign);
206740b226e8Skrw 	else if ((flags & ROUND_SIZE_DOWN) == ROUND_SIZE_DOWN)
2068dbdb4107Skrw 		stop = ROUNDDOWN(stop, stopalign);
2069aef735d2Skrw 	if (stop > maxstop)
207040b226e8Skrw 		stop = maxstop;
207140b226e8Skrw 
2072aef735d2Skrw 	if (stop <= start) {
20739b5c4600Skrw 		fprintf(stderr, "not enough space\n");
2074bb12209fSkrw 		return 1;
2075aef735d2Skrw 	}
2076aef735d2Skrw 
207740b226e8Skrw 	if (start != DL_GETPOFFSET(pp))
207840b226e8Skrw 		DL_SETPOFFSET(pp, start);
2079aef735d2Skrw 	if (stop != DL_GETPOFFSET(pp) + DL_GETPSIZE(pp))
208040b226e8Skrw 		DL_SETPSIZE(pp, stop - start);
208140b226e8Skrw 
2082bb12209fSkrw 	return 0;
208340b226e8Skrw }
2084