xref: /openbsd/sbin/disklabel/editor.c (revision 528915f5)
1*528915f5Smillert /*	$OpenBSD: editor.c,v 1.54 1999/03/21 17:22:33 millert Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
45362a395Smillert  * Copyright (c) 1997-1999 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  * All rights reserved.
66fe57b42Smillert  *
76fe57b42Smillert  * Redistribution and use in source and binary forms, with or without
86fe57b42Smillert  * modification, are permitted provided that the following conditions
96fe57b42Smillert  * are met:
106fe57b42Smillert  * 1. Redistributions of source code must retain the above copyright
116fe57b42Smillert  *    notice, this list of conditions and the following disclaimer.
126fe57b42Smillert  * 2. Redistributions in binary form must reproduce the above copyright
136fe57b42Smillert  *    notice, this list of conditions and the following disclaimer in the
146fe57b42Smillert  *    documentation and/or other materials provided with the distribution.
159141dda3Smillert  * 3. The name of the author may not be used to endorse or promote products
166fe57b42Smillert  *    derived from this software without specific prior written permission.
176fe57b42Smillert  *
186fe57b42Smillert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
196fe57b42Smillert  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
206fe57b42Smillert  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
216fe57b42Smillert  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
226fe57b42Smillert  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
236fe57b42Smillert  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
246fe57b42Smillert  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
256fe57b42Smillert  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
266fe57b42Smillert  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
276fe57b42Smillert  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286fe57b42Smillert  */
296fe57b42Smillert 
306fe57b42Smillert #ifndef lint
31*528915f5Smillert static char rcsid[] = "$OpenBSD: editor.c,v 1.54 1999/03/21 17:22:33 millert Exp $";
326fe57b42Smillert #endif /* not lint */
336fe57b42Smillert 
346fe57b42Smillert #include <sys/types.h>
356fe57b42Smillert #include <sys/param.h>
366fe57b42Smillert #define	DKTYPENAMES
376fe57b42Smillert #include <sys/disklabel.h>
386fe57b42Smillert 
396fe57b42Smillert #include <ufs/ffs/fs.h>
406fe57b42Smillert 
416fe57b42Smillert #include <ctype.h>
426fe57b42Smillert #include <err.h>
436fe57b42Smillert #include <errno.h>
446fe57b42Smillert #include <string.h>
45803ff7d5Smillert #include <libgen.h>
466fe57b42Smillert #include <stdio.h>
476fe57b42Smillert #include <stdlib.h>
486fe57b42Smillert #include <unistd.h>
496fe57b42Smillert 
504793b14cSmillert #include "pathnames.h"
514793b14cSmillert 
526fe57b42Smillert /* flags for getuint() */
536fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
546fe57b42Smillert #define	DO_ROUNDING	0x00000002
556fe57b42Smillert 
56f98aebd4Smillert #ifndef NUMBOOT
57f98aebd4Smillert #define NUMBOOT 0
58f98aebd4Smillert #endif
59f98aebd4Smillert 
6096a888c6Smillert /* structure to describe a portion of a disk */
6196a888c6Smillert struct diskchunk {
6296a888c6Smillert 	u_int32_t start;
6396a888c6Smillert 	u_int32_t stop;
6496a888c6Smillert };
6596a888c6Smillert 
663f843443Smillert /* used when sorting mountpoints in mpsave() */
673f843443Smillert struct mountinfo {
683f843443Smillert 	char *mountpoint;
693f843443Smillert 	int partno;
703f843443Smillert };
713f843443Smillert 
726fe57b42Smillert void	edit_parms __P((struct disklabel *, u_int32_t *));
73bd6726faSmillert int	editor __P((struct disklabel *, int, char *, char *));
74bd6726faSmillert void	editor_add __P((struct disklabel *, char **, u_int32_t *, char *));
756fe57b42Smillert void	editor_change __P((struct disklabel *, u_int32_t *, char *));
76c0bdc608Smillert void	editor_countfree __P((struct disklabel *, u_int32_t *));
77bd6726faSmillert void	editor_delete __P((struct disklabel *, char **, u_int32_t *, char *));
78bd6726faSmillert void	editor_display __P((struct disklabel *, char **, u_int32_t *, char));
79617e6e4aSmillert void	editor_help __P((char *));
80bd6726faSmillert void	editor_modify __P((struct disklabel *, char **, u_int32_t *, char *));
81bd6726faSmillert void	editor_name __P((struct disklabel *, char **, char *));
826fe57b42Smillert char	*getstring __P((struct disklabel *, char *, char *, char *));
834b9a3bdaSmillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, u_int32_t, int));
846fe57b42Smillert int	has_overlap __P((struct disklabel *, u_int32_t *, int));
856fe57b42Smillert void	make_contiguous __P((struct disklabel *));
8696a888c6Smillert u_int32_t next_offset __P((struct disklabel *, struct partition *));
876fe57b42Smillert int	partition_cmp __P((const void *, const void *));
88a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));
89803ff7d5Smillert void	getdisktype __P((struct disklabel *, char *, char *));
9096a888c6Smillert void	find_bounds __P((struct disklabel *));
91e8e8bdb7Sart void	set_bounds __P((struct disklabel *, u_int32_t *));
9296a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *));
93bd6726faSmillert char **	mpcopy __P((char **, char **));
943f843443Smillert int	micmp __P((const void *, const void *));
95bd6726faSmillert int	mpequal __P((char **, char **));
96bd6726faSmillert int	mpsave __P((struct disklabel *, char **, char *, char *));
9724a2c1a4Smillert int	get_bsize __P((struct disklabel *, int));
9824a2c1a4Smillert int	get_cpg __P((struct disklabel *, int));
9924a2c1a4Smillert int	get_fsize __P((struct disklabel *, int));
10024a2c1a4Smillert int	get_fstype __P((struct disklabel *, int));
10124a2c1a4Smillert int	get_mp __P((struct disklabel *, char **, int));
10224a2c1a4Smillert int	get_offset __P((struct disklabel *, int));
10324a2c1a4Smillert int	get_size __P((struct disklabel *, int, u_int32_t *, int));
10496a888c6Smillert 
10596a888c6Smillert static u_int32_t starting_sector;
10696a888c6Smillert static u_int32_t ending_sector;
1076fe57b42Smillert 
1086fe57b42Smillert /* from disklabel.c */
1096fe57b42Smillert int	checklabel __P((struct disklabel *));
1106fe57b42Smillert void	display __P((FILE *, struct disklabel *));
111bd6726faSmillert void	display_partition __P((FILE *, struct disklabel *, char **, int, char, int));
112af98caf3Sderaadt int	width_partition __P((struct disklabel *, int));
113af98caf3Sderaadt 
1146fe57b42Smillert struct disklabel *readlabel __P((int));
1156fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int));
1166fe57b42Smillert int	writelabel __P((int, char *, struct disklabel *));
1176fe57b42Smillert extern	char *bootarea, *specname;
11869220492Smillert extern	int donothing;
1194793b14cSmillert #ifdef DOSLABEL
1204793b14cSmillert struct dos_partition *dosdp;	/* DOS partition, if found */
1214793b14cSmillert #endif
1226fe57b42Smillert 
1236fe57b42Smillert /*
1246fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
1256fe57b42Smillert  */
1266fe57b42Smillert int
127bd6726faSmillert editor(lp, f, dev, fstabfile)
1286fe57b42Smillert 	struct disklabel *lp;
1296fe57b42Smillert 	int f;
130803ff7d5Smillert 	char *dev;
131bd6726faSmillert 	char *fstabfile;
1326fe57b42Smillert {
1336fe57b42Smillert 	struct disklabel lastlabel, tmplabel, label = *lp;
13496a888c6Smillert 	struct partition *pp;
13596a888c6Smillert 	u_int32_t freesectors;
1366fe57b42Smillert 	FILE *fp;
1376fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
138bd6726faSmillert 	char **mountpoints = NULL, **omountpoints, **tmpmountpoints;
139bd6726faSmillert 
140bd6726faSmillert 	/* Alloc and init mount point info */
141bd6726faSmillert 	if (fstabfile) {
142bd6726faSmillert 		if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
143bd6726faSmillert 		    !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
144bd6726faSmillert 		    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
145bd6726faSmillert 			errx(4, "out of memory");
146bd6726faSmillert 	}
1476fe57b42Smillert 
14896a888c6Smillert 	/* Don't allow disk type of "unknown" */
149803ff7d5Smillert 	getdisktype(&label, "You need to specify a type for this disk.", dev);
1506fe57b42Smillert 
15196a888c6Smillert 	/* How big is the OpenBSD portion of the disk?  */
15296a888c6Smillert 	find_bounds(&label);
15396a888c6Smillert 
15496a888c6Smillert 	/* Set freesectors based on bounds and initial label */
155c0bdc608Smillert 	editor_countfree(&label, &freesectors);
15696a888c6Smillert 
15796a888c6Smillert 	/* Make sure there is no partition overlap. */
15896a888c6Smillert 	if (has_overlap(&label, &freesectors, 1))
1596fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1606fe57b42Smillert 
16196a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
16296a888c6Smillert 	pp = &label.d_partitions[2];
16396a888c6Smillert 	if (label.d_npartitions < 3 || pp->p_size == 0) {
16496a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
16596a888c6Smillert 		if (label.d_npartitions < 3)
16696a888c6Smillert 			label.d_npartitions = 3;
16796a888c6Smillert 		pp->p_offset = 0;
16896a888c6Smillert 		pp->p_size = label.d_secperunit;
16996a888c6Smillert 		pp->p_fstype = FS_UNUSED;
17096a888c6Smillert 		pp->p_fsize = pp->p_frag = pp->p_cpg = 0;
17196a888c6Smillert 	}
1720f820bbbSmillert 
1736fe57b42Smillert #ifdef CYLCHECK
1746fe57b42Smillert 	puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically.");
1756fe57b42Smillert #endif
1766fe57b42Smillert 
177bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
17855403f76Smillert 	if (strcmp(label.d_packname, "fictitious") == 0) {
17955403f76Smillert 		if (label.d_bbsize == 0)
18055403f76Smillert 			label.d_bbsize = BBSIZE;
18155403f76Smillert 		if (label.d_sbsize == 0)
18255403f76Smillert 			label.d_sbsize = SBSIZE;
18355403f76Smillert 	}
184f98aebd4Smillert 
185440b1d70Smillert 	/* Interleave must be >= 1 */
186440b1d70Smillert 	if (label.d_interleave == 0)
187440b1d70Smillert 		label.d_interleave = 1;
188440b1d70Smillert 
18996a888c6Smillert 	puts("\nInitial label editor (enter '?' for help at any prompt)");
1906fe57b42Smillert 	lastlabel = label;
1916fe57b42Smillert 	for (;;) {
1926fe57b42Smillert 		fputs("> ", stdout);
1936fe57b42Smillert 		fflush(stdout);
1946fe57b42Smillert 		rewind(stdin);
1956e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1966e0becc5Smillert 			putchar('\n');
1976e0becc5Smillert 			buf[0] = 'q';
1986e0becc5Smillert 			buf[1] = '\0';
1996e0becc5Smillert 		}
200260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
201260513deSmillert 			continue;
202260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2036fe57b42Smillert 
2046fe57b42Smillert 		switch (*cmd) {
2056fe57b42Smillert 
2066fe57b42Smillert 		case '?':
207ea37abd3Sderaadt 		case 'h':
208617e6e4aSmillert 			editor_help(arg ? arg : "");
2096fe57b42Smillert 			break;
2106fe57b42Smillert 
2116fe57b42Smillert 		case 'a':
2126fe57b42Smillert 			tmplabel = lastlabel;
2136fe57b42Smillert 			lastlabel = label;
214bd6726faSmillert 			if (mountpoints != NULL) {
215bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
216bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
217bd6726faSmillert 			}
218bd6726faSmillert 			editor_add(&label, mountpoints, &freesectors, arg);
21996a888c6Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
22096a888c6Smillert 				lastlabel = tmplabel;
221bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
222bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
22396a888c6Smillert 			break;
22496a888c6Smillert 
22596a888c6Smillert 		case 'b':
22696a888c6Smillert 			tmplabel = lastlabel;
22796a888c6Smillert 			lastlabel = label;
228e8e8bdb7Sart 			set_bounds(&label, &freesectors);
2296fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2306fe57b42Smillert 				lastlabel = tmplabel;
2316fe57b42Smillert 			break;
2326fe57b42Smillert 
2336fe57b42Smillert 		case 'c':
2346fe57b42Smillert 			tmplabel = lastlabel;
2356fe57b42Smillert 			lastlabel = label;
23696a888c6Smillert 			editor_change(&label, &freesectors, arg);
2376fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2386fe57b42Smillert 				lastlabel = tmplabel;
2396fe57b42Smillert 			break;
2406fe57b42Smillert 
2416fe57b42Smillert 		case 'd':
2426fe57b42Smillert 			tmplabel = lastlabel;
2436fe57b42Smillert 			lastlabel = label;
244bd6726faSmillert 			if (mountpoints != NULL) {
245bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
246bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
247bd6726faSmillert 			}
248bd6726faSmillert 			editor_delete(&label, mountpoints, &freesectors, arg);
2496fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2506fe57b42Smillert 				lastlabel = tmplabel;
251bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
252bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
2536fe57b42Smillert 			break;
2546fe57b42Smillert 
2556fe57b42Smillert 		case 'm':
2566fe57b42Smillert 			tmplabel = lastlabel;
2576fe57b42Smillert 			lastlabel = label;
258bd6726faSmillert 			if (mountpoints != NULL) {
259bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
260bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
261bd6726faSmillert 			}
262bd6726faSmillert 			editor_modify(&label, mountpoints, &freesectors, arg);
2636fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2646fe57b42Smillert 				lastlabel = tmplabel;
265bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
266bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
267bd6726faSmillert 			break;
268bd6726faSmillert 
269bd6726faSmillert 		case 'n':
270bd6726faSmillert 			if (mountpoints == NULL) {
271bd6726faSmillert 				fputs("This option is not valid when run "
272bd6726faSmillert 				    "without the -F flag.\n", stderr);
273bd6726faSmillert 				break;
274bd6726faSmillert 			}
275bd6726faSmillert 			mpcopy(tmpmountpoints, omountpoints);
276bd6726faSmillert 			mpcopy(omountpoints, mountpoints);
277bd6726faSmillert 			editor_name(&label, mountpoints, arg);
278bd6726faSmillert 			if (mpequal(omountpoints, tmpmountpoints))
279bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
2806fe57b42Smillert 			break;
2816fe57b42Smillert 
2826fe57b42Smillert 		case 'p':
283bd6726faSmillert 			editor_display(&label, mountpoints, &freesectors,
284bd6726faSmillert 			    arg ? *arg : 0);
2856fe57b42Smillert 			break;
2866fe57b42Smillert 
287508086e9Smillert 		case 'M': {
288508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
289508086e9Smillert 			char *pager;
2905d12b01bSderaadt 			extern char manpage[];
2915d12b01bSderaadt 
292508086e9Smillert 			if ((pager = getenv("PAGER")) == NULL)
293508086e9Smillert 				pager = _PATH_LESS;
294508086e9Smillert 			if ((fp = popen(pager, "w")) != NULL) {
2955d12b01bSderaadt 				(void) fwrite(manpage, strlen(manpage), 1, fp);
2965d12b01bSderaadt 				pclose(fp);
297508086e9Smillert 			} else
298508086e9Smillert 				warn("unable to execute %s", pager);
299508086e9Smillert 
300508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3015d12b01bSderaadt 			break;
302508086e9Smillert 		}
3035d12b01bSderaadt 
3046fe57b42Smillert 		case 'q':
30569220492Smillert 			if (donothing) {
30669220492Smillert 				puts("In no change mode, not writing label.");
30769220492Smillert 				return(1);
30869220492Smillert 			}
309bd6726faSmillert 			/* Save mountpoint info if there is any. */
310bd6726faSmillert 			if (mountpoints != NULL)
311bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
3126fe57b42Smillert 			if (memcmp(lp, &label, sizeof(label)) == 0) {
313bd6726faSmillert 				puts("No label changes.");
3146fe57b42Smillert 				return(1);
3156fe57b42Smillert 			}
3166fe57b42Smillert 			do {
317bd6726faSmillert 				arg = getstring(&label, "Save changes?",
3186fe57b42Smillert 				    "Save changes you have made to the label?",
3196fe57b42Smillert 				    "n");
32096a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
32196a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
3226fe57b42Smillert 				*lp = label;
3236fe57b42Smillert 				if (writelabel(f, bootarea, lp) == 0)
3246fe57b42Smillert 					return(0);
3256fe57b42Smillert 			}
3266fe57b42Smillert 			return(1);
3276fe57b42Smillert 			/* NOTREACHED */
3286fe57b42Smillert 			break;
3296fe57b42Smillert 
330c0bdc608Smillert 		case 'r':
331c0bdc608Smillert 		    /* Recalculate free space */
332c0bdc608Smillert 		    editor_countfree(&label, &freesectors);
333c0bdc608Smillert 		    puts("Recalculated free space.");
334c0bdc608Smillert 		    break;
335c0bdc608Smillert 
3366fe57b42Smillert 		case 's':
3376fe57b42Smillert 			if (arg == NULL) {
338260513deSmillert 				arg = getstring(lp, "Filename",
3396fe57b42Smillert 				    "Name of the file to save label into.",
3406fe57b42Smillert 				    NULL);
34196a888c6Smillert 				if (arg == NULL && *arg == '\0')
3426fe57b42Smillert 					break;
3436fe57b42Smillert 			}
3446fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
3456fe57b42Smillert 				warn("cannot open %s", arg);
3466fe57b42Smillert 			} else {
3476fe57b42Smillert 				display(fp, &label);
3486fe57b42Smillert 				(void)fclose(fp);
3496fe57b42Smillert 			}
3506fe57b42Smillert 			break;
3516fe57b42Smillert 
3526fe57b42Smillert 		case 'u':
353bd6726faSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0 &&
354bd6726faSmillert 			    mountpoints != NULL &&
355bd6726faSmillert 			    mpequal(mountpoints, omountpoints)) {
3566fe57b42Smillert 				puts("Nothing to undo!");
3576fe57b42Smillert 			} else {
3586fe57b42Smillert 				tmplabel = label;
3596fe57b42Smillert 				label = lastlabel;
3606fe57b42Smillert 				lastlabel = tmplabel;
361c0bdc608Smillert 				/* Recalculate free space */
362c0bdc608Smillert 				editor_countfree(&label, &freesectors);
363bd6726faSmillert 				/* Restore mountpoints */
364bd6726faSmillert 				if (mountpoints != NULL)
365bd6726faSmillert 					mpcopy(mountpoints, omountpoints);
3666fe57b42Smillert 				puts("Last change undone.");
3676fe57b42Smillert 			}
3686fe57b42Smillert 			break;
3696fe57b42Smillert 
370040947cfSmillert 		case 'w':
371bd6726faSmillert 			if (donothing)  {
372040947cfSmillert 				puts("In no change mode, not writing label.");
373bd6726faSmillert 				break;
374bd6726faSmillert 			}
375bd6726faSmillert 			/* Save mountpoint info if there is any. */
376bd6726faSmillert 			if (mountpoints != NULL)
377bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
378bd6726faSmillert 			/* Save label if it has changed. */
379bd6726faSmillert 			if (memcmp(lp, &label, sizeof(label)) == 0)
380bd6726faSmillert 				puts("No label changes.");
381040947cfSmillert 			else if (writelabel(f, bootarea, &label) != 0)
382040947cfSmillert 				warnx("unable to write label");
3835af08e9cSmillert 			else
3845af08e9cSmillert 				*lp = label;
385040947cfSmillert 			break;
386040947cfSmillert 
3876fe57b42Smillert 		case 'x':
3886fe57b42Smillert 			return(1);
3896fe57b42Smillert 			break;
3906fe57b42Smillert 
3916fe57b42Smillert 		case '\n':
3926fe57b42Smillert 			break;
3936fe57b42Smillert 
3946fe57b42Smillert 		case 'e':
3956fe57b42Smillert 			tmplabel = lastlabel;
3966fe57b42Smillert 			lastlabel = label;
39796a888c6Smillert 			edit_parms(&label, &freesectors);
3986fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
3996fe57b42Smillert 				lastlabel = tmplabel;
4006fe57b42Smillert 			break;
4016fe57b42Smillert 
4026fe57b42Smillert 		default:
4036fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4046fe57b42Smillert 			break;
4056fe57b42Smillert 		}
4066fe57b42Smillert 	}
4076fe57b42Smillert }
4086fe57b42Smillert 
4096fe57b42Smillert /*
4106fe57b42Smillert  * Add a new partition.
4116fe57b42Smillert  */
4126fe57b42Smillert void
413bd6726faSmillert editor_add(lp, mp, freep, p)
4146fe57b42Smillert 	struct disklabel *lp;
415bd6726faSmillert 	char **mp;
4166fe57b42Smillert 	u_int32_t *freep;
4176fe57b42Smillert 	char *p;
4186fe57b42Smillert {
41996a888c6Smillert 	struct partition *pp;
42096a888c6Smillert 	struct diskchunk *chunks;
4216fe57b42Smillert 	char buf[BUFSIZ];
4226fe57b42Smillert 	int i, partno;
42396a888c6Smillert 	u_int32_t ui, old_offset, old_size;
4246fe57b42Smillert 
4256fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
4266fe57b42Smillert 	if (*freep == 0) {
4276fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
4286fe57b42Smillert 		    stderr);
4296fe57b42Smillert 		return;
4306fe57b42Smillert 	}
4316fe57b42Smillert 
4326fe57b42Smillert 	/* XXX - make more like other editor_* */
4336fe57b42Smillert 	if (p != NULL) {
4346fe57b42Smillert 		partno = p[0] - 'a';
435e6ab932bSmillert 		if (partno < 0 || partno == 2 || partno >= MAXPARTITIONS) {
4366fe57b42Smillert 			fprintf(stderr,
437e6ab932bSmillert 			    "Partition must be between 'a' and '%c' "
438e6ab932bSmillert 			    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
4396fe57b42Smillert 			return;
44096a888c6Smillert 		} else if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
441f6299b35Sderaadt 		    lp->d_partitions[partno].p_size != 0) {
442f6299b35Sderaadt 			fprintf(stderr,
443f6299b35Sderaadt 			    "Partition '%c' exists.  Delete it first.\n",
444f6299b35Sderaadt 			    p[0]);
445f6299b35Sderaadt 			return;
4466fe57b42Smillert 		}
4476fe57b42Smillert 	} else {
4489c5f1350Smillert 		/* Find first unused partition that is not 'c' */
4496fe57b42Smillert 		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {
4509c5f1350Smillert 			if (lp->d_partitions[partno].p_size == 0 && partno != 2)
4516fe57b42Smillert 				break;
4526fe57b42Smillert 		}
4536fe57b42Smillert 		if (partno < MAXPARTITIONS) {
4546fe57b42Smillert 			buf[0] = partno + 'a';
4556fe57b42Smillert 			buf[1] = '\0';
4566fe57b42Smillert 			p = &buf[0];
4576fe57b42Smillert 		} else
4586fe57b42Smillert 			p = NULL;
4596fe57b42Smillert 		for (;;) {
4606fe57b42Smillert 			p = getstring(lp, "partition",
4616fe57b42Smillert 			    "The letter of the new partition, a - p.", p);
46296a888c6Smillert 			if (p == NULL)
46396a888c6Smillert 				return;
4646fe57b42Smillert 			partno = p[0] - 'a';
46596a888c6Smillert 			if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
46696a888c6Smillert 			    lp->d_partitions[partno].p_size != 0) {
46796a888c6Smillert 				fprintf(stderr,
46896a888c6Smillert 				    "Partition '%c' already exists.\n", p[0]);
46996a888c6Smillert 			} else if (partno >= 0 && partno < MAXPARTITIONS)
4706fe57b42Smillert 				break;
4716fe57b42Smillert 			fprintf(stderr,
4726fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
4736fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
4746fe57b42Smillert 		}
4756fe57b42Smillert 	}
47696a888c6Smillert 
47796a888c6Smillert 	/* Increase d_npartitions if necesary */
47896a888c6Smillert 	if (partno >= lp->d_npartitions)
47996a888c6Smillert 		lp->d_npartitions = partno + 1;
48096a888c6Smillert 
48196a888c6Smillert 	/* Set defaults */
4826fe57b42Smillert 	pp = &lp->d_partitions[partno];
4836fe57b42Smillert 	if (partno >= lp->d_npartitions)
4846fe57b42Smillert 		lp->d_npartitions = partno + 1;
4856fe57b42Smillert 	memset(pp, 0, sizeof(*pp));
48696a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
4876fe57b42Smillert 	pp->p_fsize = 1024;
4886fe57b42Smillert 	pp->p_frag = 8;
4896fe57b42Smillert 	pp->p_cpg = 16;
49096a888c6Smillert 	pp->p_size = *freep;
49196a888c6Smillert 	pp->p_offset = next_offset(lp, pp);	/* must be computed last */
492f98aebd4Smillert #if NUMBOOT == 1
493f98aebd4Smillert 	/* Don't clobber boot blocks */
494f98aebd4Smillert 	if (pp->p_offset == 0) {
4958dddfaa0Smillert 		pp->p_offset = lp->d_secpercyl;
4968dddfaa0Smillert 		pp->p_size -= lp->d_secpercyl;
497f98aebd4Smillert 	}
498f98aebd4Smillert #endif
49996a888c6Smillert 	old_offset = pp->p_offset;
50096a888c6Smillert 	old_size = pp->p_size;
50196a888c6Smillert 
50296a888c6Smillert getoff1:
50396a888c6Smillert 	/* Get offset */
50424a2c1a4Smillert 	if (get_offset(lp, partno) != 0) {
50596a888c6Smillert 		pp->p_size = 0;			/* effective delete */
50696a888c6Smillert 		return;
50796a888c6Smillert 	}
50896a888c6Smillert 
50996a888c6Smillert 	/* Recompute recommended size based on new offset */
51096a888c6Smillert 	ui = pp->p_fstype;
51196a888c6Smillert 	pp->p_fstype = FS_UNUSED;
51296a888c6Smillert 	chunks = free_chunks(lp);
51396a888c6Smillert 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
51496a888c6Smillert 		if (pp->p_offset >= chunks[i].start &&
51596a888c6Smillert 		    pp->p_offset < chunks[i].stop) {
51696a888c6Smillert 			pp->p_size = chunks[i].stop - pp->p_offset;
51796a888c6Smillert 			break;
51896a888c6Smillert 		}
51996a888c6Smillert 	}
52096a888c6Smillert 	pp->p_fstype = ui;
52196a888c6Smillert 
52296a888c6Smillert 	/* Get size */
52324a2c1a4Smillert 	if (get_size(lp, partno, freep, 1) != 0 || pp->p_size == 0) {
52496a888c6Smillert 		pp->p_size = 0;			/* effective delete */
52596a888c6Smillert 		return;
52696a888c6Smillert 	}
52796a888c6Smillert 
52896a888c6Smillert 	/* Check for overlap */
52996a888c6Smillert 	if (has_overlap(lp, freep, 0)) {
5304793b14cSmillert 		printf("\nPlease re-enter an offset and size for partition "
5314793b14cSmillert 		    "%c.\n", 'a' + partno);
53296a888c6Smillert 		pp->p_offset = old_offset;
53396a888c6Smillert 		pp->p_size = old_size;
53496a888c6Smillert 		goto getoff1;		/* Yeah, I know... */
53596a888c6Smillert 	}
5366fe57b42Smillert 
53724a2c1a4Smillert 	/* Get filesystem type */
53824a2c1a4Smillert 	if (get_fstype(lp, partno) != 0) {
53996a888c6Smillert 		pp->p_size = 0;			/* effective delete */
54096a888c6Smillert 		return;
54196a888c6Smillert 	}
5426fe57b42Smillert 
5436fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
54424a2c1a4Smillert 		/* Get fsize */
54524a2c1a4Smillert 		if (get_fsize(lp, partno) != 0) {
54696a888c6Smillert 			pp->p_size = 0;			/* effective delete */
54796a888c6Smillert 			return;
5486fe57b42Smillert 		}
5496fe57b42Smillert 
55024a2c1a4Smillert 		/* Get bsize */
55124a2c1a4Smillert 		if (get_bsize(lp, partno) != 0) {
55296a888c6Smillert 			pp->p_size = 0;			/* effective delete */
55396a888c6Smillert 			return;
5546fe57b42Smillert 		}
5556fe57b42Smillert 
5566fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
5576fe57b42Smillert 			/* get cpg */
55824a2c1a4Smillert 			if (get_cpg(lp, partno) != 0) {
55996a888c6Smillert 				pp->p_size = 0;		/* effective delete */
56096a888c6Smillert 				return;
5616fe57b42Smillert 			}
5626fe57b42Smillert 		}
56324a2c1a4Smillert 
564bd6726faSmillert 		/* get mount point */
56524a2c1a4Smillert 		if (get_mp(lp, mp, partno) != 0) {
566bd6726faSmillert 			pp->p_size = 0;			/* effective delete */
567bd6726faSmillert 			return;
568bd6726faSmillert 		}
5696fe57b42Smillert 	}
57096a888c6Smillert 	/* Update free sector count and make sure things stay contiguous. */
5716fe57b42Smillert 	*freep -= pp->p_size;
57296a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
57396a888c6Smillert 	    has_overlap(lp, freep, -1))
5746fe57b42Smillert 		make_contiguous(lp);
5756fe57b42Smillert }
5766fe57b42Smillert 
5776fe57b42Smillert /*
578bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
579bd6726faSmillert  */
580bd6726faSmillert void
581bd6726faSmillert editor_name(lp, mp, p)
582bd6726faSmillert 	struct disklabel *lp;
583bd6726faSmillert 	char **mp;
584bd6726faSmillert 	char *p;
585bd6726faSmillert {
586bd6726faSmillert 	struct partition *pp;
587bd6726faSmillert 	int partno;
588bd6726faSmillert 
589bd6726faSmillert 	/* Change which partition? */
590bd6726faSmillert 	if (p == NULL) {
591bd6726faSmillert 		p = getstring(lp, "partition to name",
592bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
593bd6726faSmillert 	}
594bd6726faSmillert 	if (p == NULL) {
595bd6726faSmillert 		fputs("Command aborted\n", stderr);
596bd6726faSmillert 		return;
597bd6726faSmillert 	}
598bd6726faSmillert 	partno = p[0] - 'a';
599bd6726faSmillert 	pp = &lp->d_partitions[partno];
600bd6726faSmillert 	if (partno < 0 || partno >= lp->d_npartitions) {
601bd6726faSmillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
602bd6726faSmillert 		    'a' + lp->d_npartitions - 1);
603bd6726faSmillert 		return;
604bd6726faSmillert 	} else if (partno >= lp->d_npartitions ||
605bd6726faSmillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
606bd6726faSmillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
607bd6726faSmillert 		return;
608bd6726faSmillert 	}
609bd6726faSmillert 
610bd6726faSmillert 	/* Not all fstypes can be named */
611bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
612bd6726faSmillert 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER) {
613bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
614bd6726faSmillert 		    fstypesnames[lp->d_partitions[partno].p_fstype]);
615bd6726faSmillert 		return;
616bd6726faSmillert 	}
617bd6726faSmillert 
618ddaff619Smillert 	get_mp(lp, mp, partno);
619bd6726faSmillert }
620bd6726faSmillert 
621bd6726faSmillert /*
6226fe57b42Smillert  * Change an existing partition.
6236fe57b42Smillert  */
6246fe57b42Smillert void
625bd6726faSmillert editor_modify(lp, mp, freep, p)
6266fe57b42Smillert 	struct disklabel *lp;
627bd6726faSmillert 	char **mp;
6286fe57b42Smillert 	u_int32_t *freep;
6296fe57b42Smillert 	char *p;
6306fe57b42Smillert {
6316fe57b42Smillert 	struct partition origpart, *pp;
6326fe57b42Smillert 	u_int32_t ui;
6336fe57b42Smillert 	int partno;
6346fe57b42Smillert 
6356fe57b42Smillert 	/* Change which partition? */
6366fe57b42Smillert 	if (p == NULL) {
6376fe57b42Smillert 		p = getstring(lp, "partition to modify",
6386fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
6396fe57b42Smillert 	}
64096a888c6Smillert 	if (p == NULL) {
64196a888c6Smillert 		fputs("Command aborted\n", stderr);
64296a888c6Smillert 		return;
64396a888c6Smillert 	}
6446fe57b42Smillert 	partno = p[0] - 'a';
6456fe57b42Smillert 	pp = &lp->d_partitions[partno];
6466fe57b42Smillert 	origpart = lp->d_partitions[partno];
6476fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
6486fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
6496fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
6506fe57b42Smillert 		return;
6516fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
6526fe57b42Smillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
6536fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
6546fe57b42Smillert 		return;
6556fe57b42Smillert 	}
6566fe57b42Smillert 
6576fe57b42Smillert 	/* Get filesystem type */
65824a2c1a4Smillert 	if (get_fstype(lp, partno) != 0) {
65924a2c1a4Smillert 		*pp = origpart;			/* undo changes */
66096a888c6Smillert 		return;
66196a888c6Smillert 	}
6626fe57b42Smillert 
6636fe57b42Smillert 	/* Did they disable/enable the partition? */
664229f463eSmillert 	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&
665229f463eSmillert 	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)
6666fe57b42Smillert 		*freep += origpart.p_size;
667229f463eSmillert 	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
668229f463eSmillert 	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {
6696fe57b42Smillert 		if (pp->p_size > *freep) {
6706fe57b42Smillert 			fprintf(stderr,
67196a888c6Smillert 			    "Warning, need %u sectors but there are only %u "
6726fe57b42Smillert 			    "free.  Setting size to %u.\n", pp->p_size, *freep,
6736fe57b42Smillert 			    *freep);
6746fe57b42Smillert 			pp->p_fstype = *freep;
6756fe57b42Smillert 			*freep = 0;
6766fe57b42Smillert 		} else
6776fe57b42Smillert 			*freep -= pp->p_size;		/* have enough space */
6786fe57b42Smillert 	}
6796fe57b42Smillert 
6806fe57b42Smillert getoff2:
6816fe57b42Smillert 	/* Get offset */
68224a2c1a4Smillert 	if (get_offset(lp, partno) != 0) {
68396a888c6Smillert 		*pp = origpart;			/* undo changes */
68496a888c6Smillert 		return;
6856fe57b42Smillert 	}
6866fe57b42Smillert 
6876fe57b42Smillert 	/* Get size */
68824a2c1a4Smillert 	if (get_size(lp, partno, freep, 0) != 0 || pp->p_size == 0) {
68924a2c1a4Smillert 		pp->p_size = 0;			/* effective delete */
69096a888c6Smillert 		return;
6916fe57b42Smillert 	}
6926fe57b42Smillert 
6936fe57b42Smillert 	/* Check for overlap and restore if not resolved */
6946fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
6956fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
6966fe57b42Smillert 		pp->p_offset = origpart.p_offset;
6976fe57b42Smillert 		pp->p_size = origpart.p_size;
6986fe57b42Smillert 		goto getoff2;		/* Yeah, I know... */
6996fe57b42Smillert 	}
7006fe57b42Smillert 
7016fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
7026fe57b42Smillert 		/* get fsize */
70324a2c1a4Smillert 		if (get_fsize(lp, partno) != 0) {
70496a888c6Smillert 			*pp = origpart;		/* undo changes */
70596a888c6Smillert 			return;
7066fe57b42Smillert 		}
7076fe57b42Smillert 
7086fe57b42Smillert 		/* get bsize */
70924a2c1a4Smillert 		if (get_bsize(lp, partno) != 0) {
71096a888c6Smillert 			*pp = origpart;		/* undo changes */
71196a888c6Smillert 			return;
7126fe57b42Smillert 		}
7136fe57b42Smillert 
7146fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
7156fe57b42Smillert 			/* get cpg */
71624a2c1a4Smillert 			if (get_cpg(lp, partno) != 0) {
71796a888c6Smillert 				*pp = origpart;	/* undo changes */
71896a888c6Smillert 				return;
7196fe57b42Smillert 			}
7206fe57b42Smillert 		}
7216fe57b42Smillert 	}
7226fe57b42Smillert 
723bd6726faSmillert 	/* get mount point */
72424a2c1a4Smillert 	if (get_mp(lp, mp, partno) != 0) {
72524a2c1a4Smillert 		*pp = origpart;			/* undo changes */
726bd6726faSmillert 		return;
727bd6726faSmillert 	}
728bd6726faSmillert 
7296fe57b42Smillert 	/* Make sure things stay contiguous. */
73096a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
73196a888c6Smillert 	    has_overlap(lp, freep, -1))
7326fe57b42Smillert 		make_contiguous(lp);
7336fe57b42Smillert }
7346fe57b42Smillert 
7356fe57b42Smillert /*
7366fe57b42Smillert  * Delete an existing partition.
7376fe57b42Smillert  */
7386fe57b42Smillert void
739bd6726faSmillert editor_delete(lp, mp, freep, p)
7406fe57b42Smillert 	struct disklabel *lp;
741bd6726faSmillert 	char **mp;
7426fe57b42Smillert 	u_int32_t *freep;
7436fe57b42Smillert 	char *p;
7446fe57b42Smillert {
7456fe57b42Smillert 	int c;
7466fe57b42Smillert 
7476fe57b42Smillert 	if (p == NULL) {
7486fe57b42Smillert 		p = getstring(lp, "partition to delete",
749945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
750945ae268Smillert 		    NULL);
7516fe57b42Smillert 	}
75296a888c6Smillert 	if (p == NULL) {
75396a888c6Smillert 		fputs("Command aborted\n", stderr);
75496a888c6Smillert 		return;
75596a888c6Smillert 	}
756945ae268Smillert 	if (p[0] == '*') {
757945ae268Smillert 		for (c = 0; c < lp->d_npartitions; c++) {
758945ae268Smillert 			if (c == 2)
759945ae268Smillert 				continue;
760945ae268Smillert 
761945ae268Smillert 			/* Update free sector count. */
762945ae268Smillert 			if (lp->d_partitions[c].p_fstype != FS_UNUSED &&
763945ae268Smillert 			    lp->d_partitions[c].p_fstype != FS_BOOT &&
764945ae268Smillert 			    lp->d_partitions[c].p_size != 0)
765945ae268Smillert 				*freep += lp->d_partitions[c].p_size;
766945ae268Smillert 
767945ae268Smillert 			(void)memset(&lp->d_partitions[c], 0,
768945ae268Smillert 			    sizeof(lp->d_partitions[c]));
769945ae268Smillert 		}
770945ae268Smillert 		return;
771945ae268Smillert 	}
7726fe57b42Smillert 	c = p[0] - 'a';
7736fe57b42Smillert 	if (c < 0 || c >= lp->d_npartitions)
7746fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
7756fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
7766fe57b42Smillert 	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==
7776fe57b42Smillert 	    FS_UNUSED && lp->d_partitions[c].p_size == 0))
7786fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);
7796fe57b42Smillert 	else if (c == 2)
780617e6e4aSmillert 		fputs(
781617e6e4aSmillert "You may not delete the 'c' partition.  The 'c' partition must exist and\n"
782617e6e4aSmillert "should span the entire disk.  By default it is of type 'unused' and so\n"
783617e6e4aSmillert "does not take up any space.\n", stderr);
7846fe57b42Smillert 	else {
78596a888c6Smillert 		/* Update free sector count. */
786e49c5d78Smillert 		if (lp->d_partitions[c].p_offset < ending_sector &&
787e49c5d78Smillert 		    lp->d_partitions[c].p_offset >= starting_sector &&
788e49c5d78Smillert 		    lp->d_partitions[c].p_fstype != FS_UNUSED &&
789229f463eSmillert 		    lp->d_partitions[c].p_fstype != FS_BOOT &&
7906fe57b42Smillert 		    lp->d_partitions[c].p_size != 0)
7916fe57b42Smillert 			*freep += lp->d_partitions[c].p_size;
7926fe57b42Smillert 
7936fe57b42Smillert 		/* Really delete it (as opposed to just setting to "unused") */
7946fe57b42Smillert 		(void)memset(&lp->d_partitions[c], 0,
7956fe57b42Smillert 		    sizeof(lp->d_partitions[c]));
7966fe57b42Smillert 	}
797bd6726faSmillert 	if (mp != NULL && mp[c] != NULL) {
798bd6726faSmillert 		free(mp[c]);
799bd6726faSmillert 		mp[c] = NULL;
800bd6726faSmillert 	}
8016fe57b42Smillert }
8026fe57b42Smillert 
8036fe57b42Smillert /*
8046fe57b42Smillert  * Simplified display() for use with the builtin editor.
8056fe57b42Smillert  */
8066fe57b42Smillert void
807bd6726faSmillert editor_display(lp, mp, freep, unit)
8086fe57b42Smillert 	struct disklabel *lp;
809bd6726faSmillert 	char **mp;
8106fe57b42Smillert 	u_int32_t *freep;
8116fe57b42Smillert 	char unit;
8126fe57b42Smillert {
8136fe57b42Smillert 	int i;
814af98caf3Sderaadt 	int width;
8156fe57b42Smillert 
8166fe57b42Smillert 	printf("device: %s\n", specname);
8170f820bbbSmillert 	printf("type: %s\n", dktypenames[lp->d_type]);
8186fe57b42Smillert 	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
8196fe57b42Smillert 	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
8206fe57b42Smillert 	printf("bytes/sector: %ld\n", (long)lp->d_secsize);
8216fe57b42Smillert 	printf("sectors/track: %ld\n", (long)lp->d_nsectors);
8226fe57b42Smillert 	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);
8236fe57b42Smillert 	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);
8246fe57b42Smillert 	printf("cylinders: %ld\n", (long)lp->d_ncylinders);
8256fe57b42Smillert 	printf("total sectors: %ld\n", (long)lp->d_secperunit);
8266fe57b42Smillert 	printf("free sectors: %u\n", *freep);
8276fe57b42Smillert 	printf("rpm: %ld\n", (long)lp->d_rpm);
8286fe57b42Smillert 	printf("\n%d partitions:\n", lp->d_npartitions);
829af98caf3Sderaadt 	width = width_partition(lp, unit);
830af98caf3Sderaadt 	printf("#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n",
831af98caf3Sderaadt 		width, width, "size", width, width, "offset");
8326fe57b42Smillert 	for (i = 0; i < lp->d_npartitions; i++)
833bd6726faSmillert 		display_partition(stdout, lp, mp, i, unit, width);
8346fe57b42Smillert }
8356fe57b42Smillert 
8366fe57b42Smillert /*
8376fe57b42Smillert  * Find the next reasonable starting offset and returns it.
83896a888c6Smillert  * Assumes there is a least one free sector left (returns 0 if not).
8396fe57b42Smillert  */
8406fe57b42Smillert u_int32_t
84196a888c6Smillert next_offset(lp, pp)
8426fe57b42Smillert 	struct disklabel *lp;
84396a888c6Smillert 	struct partition *pp;
8446fe57b42Smillert {
845f0b4d0a9Smillert 	struct partition **spp;
84696a888c6Smillert 	struct diskchunk *chunks;
847f0b4d0a9Smillert 	u_int16_t npartitions;
84896a888c6Smillert 	u_int32_t new_offset, new_size;
84996a888c6Smillert 	int i, good_offset;
8506fe57b42Smillert 
851a7e61405Smillert 	/* Get a sorted list of the partitions */
85296a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
85396a888c6Smillert 		return(0);
854f0b4d0a9Smillert 
85596a888c6Smillert 	new_offset = starting_sector;
856f0b4d0a9Smillert 	for (i = 0; i < npartitions; i++ ) {
85796a888c6Smillert 		/* Skip the partition for which we are finding an offset */
85896a888c6Smillert 		if (pp == spp[i])
85996a888c6Smillert 			continue;
86096a888c6Smillert 
8616fe57b42Smillert 		/*
8626fe57b42Smillert 		 * Is new_offset inside this partition?  If so,
86396a888c6Smillert 		 * make it the next sector after the partition ends.
8646fe57b42Smillert 		 */
8654793b14cSmillert 		if (spp[i]->p_offset + spp[i]->p_size < ending_sector &&
8664793b14cSmillert 		    ((new_offset >= spp[i]->p_offset &&
86796a888c6Smillert 		    new_offset < spp[i]->p_offset + spp[i]->p_size) ||
86896a888c6Smillert 		    (new_offset + pp->p_size >= spp[i]->p_offset && new_offset
8694793b14cSmillert 		    + pp->p_size <= spp[i]->p_offset + spp[i]->p_size)))
870f0b4d0a9Smillert 			new_offset = spp[i]->p_offset + spp[i]->p_size;
8716fe57b42Smillert 	}
8726fe57b42Smillert 
87396a888c6Smillert 	/* Did we find a suitable offset? */
87496a888c6Smillert 	for (good_offset = 1, i = 0; i < npartitions; i++ ) {
87596a888c6Smillert 		if (new_offset + pp->p_size >= spp[i]->p_offset &&
87696a888c6Smillert 		    new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) {
87796a888c6Smillert 			/* Nope */
87896a888c6Smillert 			good_offset = 0;
87996a888c6Smillert 			break;
88096a888c6Smillert 		}
88196a888c6Smillert 	}
88296a888c6Smillert 
88396a888c6Smillert 	/* Specified size is too big, find something that fits */
88496a888c6Smillert 	if (!good_offset) {
88596a888c6Smillert 		chunks = free_chunks(lp);
88696a888c6Smillert 		new_size = 0;
88796a888c6Smillert 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
88896a888c6Smillert 			if (chunks[i].stop - chunks[i].start > new_size) {
88996a888c6Smillert 			    new_size = chunks[i].stop - chunks[i].start;
89096a888c6Smillert 			    new_offset = chunks[i].start;
89196a888c6Smillert 			}
89296a888c6Smillert 		}
8934793b14cSmillert 		/* XXX - should do something intelligent if new_size == 0 */
89496a888c6Smillert 		pp->p_size = new_size;
89596a888c6Smillert 	}
89696a888c6Smillert 
897f0b4d0a9Smillert 	(void)free(spp);
8986fe57b42Smillert 	return(new_offset);
8996fe57b42Smillert }
9006fe57b42Smillert 
9016fe57b42Smillert /*
9026fe57b42Smillert  * Change the size of an existing partition.
9036fe57b42Smillert  */
9046fe57b42Smillert void
9056fe57b42Smillert editor_change(lp, freep, p)
9066fe57b42Smillert 	struct disklabel *lp;
9076fe57b42Smillert 	u_int32_t *freep;
9086fe57b42Smillert 	char *p;
9096fe57b42Smillert {
9106fe57b42Smillert 	int partno;
9116fe57b42Smillert 	u_int32_t newsize;
9124b9a3bdaSmillert 	struct partition *pp;
9136fe57b42Smillert 
9146fe57b42Smillert 	if (p == NULL) {
9156fe57b42Smillert 		p = getstring(lp, "partition to change size",
9166fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
9176fe57b42Smillert 	}
91896a888c6Smillert 	if (p == NULL) {
91996a888c6Smillert 		fputs("Command aborted\n", stderr);
92096a888c6Smillert 		return;
92196a888c6Smillert 	}
9226fe57b42Smillert 	partno = p[0] - 'a';
9236fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
9246fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
9256fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
9266fe57b42Smillert 		return;
9276fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
928229f463eSmillert 	    lp->d_partitions[partno].p_size == 0) {
9296fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
9306fe57b42Smillert 		return;
9316fe57b42Smillert 	}
9324b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
9336fe57b42Smillert 
9346fe57b42Smillert 	printf("Partition %c is currently %u sectors in size (%u free).\n",
9354b9a3bdaSmillert 	    partno + 'a', pp->p_size, *freep);
936229f463eSmillert 	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */
9376fe57b42Smillert 	newsize = getuint(lp, partno, "new size", "Size of the partition.  "
9386fe57b42Smillert 	    "You may also say +/- amount for a relative change.",
9394b9a3bdaSmillert 	    pp->p_size, pp->p_size + *freep, pp->p_offset, DO_CONVERSIONS |
9404b9a3bdaSmillert 	    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
94196a888c6Smillert 	if (newsize == UINT_MAX - 1) {
94296a888c6Smillert 		fputs("Command aborted\n", stderr);
94396a888c6Smillert 		return;
94496a888c6Smillert 	} else if (newsize == UINT_MAX) {
9456fe57b42Smillert 		fputs("Invalid entry\n", stderr);
9466fe57b42Smillert 		return;
9474b9a3bdaSmillert 	} else if (newsize == pp->p_size)
9486fe57b42Smillert 		return;
9496fe57b42Smillert 
9504b9a3bdaSmillert 	if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT) {
9514b9a3bdaSmillert 		if (newsize > pp->p_size) {
9524b9a3bdaSmillert 			if (newsize - pp->p_size > *freep) {
9536fe57b42Smillert 				fprintf(stderr,
9546fe57b42Smillert 				    "Only %u sectors free, you asked for %u\n",
9554b9a3bdaSmillert 				    *freep, newsize - pp->p_size);
9566fe57b42Smillert 				return;
9576fe57b42Smillert 			}
9584b9a3bdaSmillert 			*freep -= newsize - pp->p_size;
9594b9a3bdaSmillert 		} else if (newsize < pp->p_size) {
9604b9a3bdaSmillert 			*freep += pp->p_size - newsize;
9616fe57b42Smillert 		}
9626fe57b42Smillert 	} else {
96396a888c6Smillert 		if (partno == 2 && newsize +
9644b9a3bdaSmillert 		    pp->p_offset > lp->d_secperunit) {
9656fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
9666fe57b42Smillert 			    stderr);
9676fe57b42Smillert 			return;
9686fe57b42Smillert 		}
9696fe57b42Smillert 	}
9704b9a3bdaSmillert 	pp->p_size = newsize;
9714b9a3bdaSmillert 	if (newsize + pp->p_offset > ending_sector ||
97296a888c6Smillert 	    has_overlap(lp, freep, -1))
9736fe57b42Smillert 		make_contiguous(lp);
9746fe57b42Smillert }
9756fe57b42Smillert 
9766fe57b42Smillert void
9776fe57b42Smillert make_contiguous(lp)
9786fe57b42Smillert 	struct disklabel *lp;
9796fe57b42Smillert {
9806fe57b42Smillert 	struct partition **spp;
9816fe57b42Smillert 	u_int16_t npartitions;
9826fe57b42Smillert 	int i;
9836fe57b42Smillert 
984a7e61405Smillert 	/* Get a sorted list of the partitions */
98596a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
98696a888c6Smillert 		return;
9876fe57b42Smillert 
9886fe57b42Smillert 	/*
989a7e61405Smillert 	 * Make everything contiguous but don't muck with start of the first one
99096a888c6Smillert 	 * or partitions not in the BSD part of the label.
9916fe57b42Smillert 	 */
99296a888c6Smillert 	for (i = 1; i < npartitions; i++) {
99396a888c6Smillert 		if (spp[i]->p_offset >= starting_sector ||
99496a888c6Smillert 		    spp[i]->p_offset < ending_sector)
99596a888c6Smillert 			spp[i]->p_offset =
99696a888c6Smillert 			    spp[i - 1]->p_offset + spp[i - 1]->p_size;
99796a888c6Smillert 	}
998f0b4d0a9Smillert 
999f0b4d0a9Smillert 	(void)free(spp);
10006fe57b42Smillert }
10016fe57b42Smillert 
10026fe57b42Smillert /*
10036fe57b42Smillert  * Sort the partitions based on starting offset.
10046fe57b42Smillert  * This assumes there can be no overlap.
10056fe57b42Smillert  */
10066fe57b42Smillert int
10076fe57b42Smillert partition_cmp(e1, e2)
10086fe57b42Smillert 	const void *e1, *e2;
10096fe57b42Smillert {
10106fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10116fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10126fe57b42Smillert 
10136fe57b42Smillert 	return((int)(p1->p_offset - p2->p_offset));
10146fe57b42Smillert }
10156fe57b42Smillert 
10166fe57b42Smillert char *
10176fe57b42Smillert getstring(lp, prompt, helpstring, oval)
10186fe57b42Smillert 	struct disklabel *lp;
10196fe57b42Smillert 	char *prompt;
10206fe57b42Smillert 	char *helpstring;
10216fe57b42Smillert 	char *oval;
10226fe57b42Smillert {
10236fe57b42Smillert 	static char buf[BUFSIZ];
10246fe57b42Smillert 	int n;
10256fe57b42Smillert 
10266fe57b42Smillert 	buf[0] = '\0';
10276fe57b42Smillert 	do {
10286fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
10296fe57b42Smillert 		fflush(stdout);
10306fe57b42Smillert 		rewind(stdin);
10316e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1032260513deSmillert 			buf[0] = '\0';
103396a888c6Smillert 			if (feof(stdin)) {
103496a888c6Smillert 				putchar('\n');
103596a888c6Smillert 				return(NULL);
103696a888c6Smillert 			}
10376e0becc5Smillert 		}
10386fe57b42Smillert 		n = strlen(buf);
10396fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
10406fe57b42Smillert 			buf[--n] = '\0';
10416fe57b42Smillert 		if (buf[0] == '?')
10426fe57b42Smillert 			puts(helpstring);
10436fe57b42Smillert 		else if (oval != NULL && buf[0] == '\0') {
10446fe57b42Smillert 			(void)strncpy(buf, oval, sizeof(buf) - 1);
10456fe57b42Smillert 			buf[sizeof(buf) - 1] = '\0';
10466fe57b42Smillert 		}
10476fe57b42Smillert 	} while (buf[0] == '?');
10486fe57b42Smillert 
10496fe57b42Smillert 	return(&buf[0]);
10506fe57b42Smillert }
10516fe57b42Smillert 
10526fe57b42Smillert /*
10536fe57b42Smillert  * Returns UINT_MAX on error
105424a2c1a4Smillert  * Usually only called by helper functions.
10556fe57b42Smillert  */
10566fe57b42Smillert u_int32_t
10574b9a3bdaSmillert getuint(lp, partno, prompt, helpstring, oval, maxval, offset, flags)
10586fe57b42Smillert 	struct disklabel *lp;
10596fe57b42Smillert 	int partno;
10606fe57b42Smillert 	char *prompt;
10616fe57b42Smillert 	char *helpstring;
10626fe57b42Smillert 	u_int32_t oval;
10636fe57b42Smillert 	u_int32_t maxval;		/* XXX - used inconsistently */
10644b9a3bdaSmillert 	u_int32_t offset;
10656fe57b42Smillert 	int flags;
10666fe57b42Smillert {
10676fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
10686fe57b42Smillert 	u_int32_t rval = oval;
10696fe57b42Smillert 	size_t n;
10706fe57b42Smillert 	int mult = 1;
107196a888c6Smillert 	double d;
10726fe57b42Smillert 
10734b9a3bdaSmillert 	/* We only care about the remainder */
10744b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
10754b9a3bdaSmillert 
10766fe57b42Smillert 	buf[0] = '\0';
10776fe57b42Smillert 	do {
10786fe57b42Smillert 		printf("%s: [%u] ", prompt, oval);
10796fe57b42Smillert 		fflush(stdout);
10806fe57b42Smillert 		rewind(stdin);
10816e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
10826e0becc5Smillert 			buf[0] = '\0';
108396a888c6Smillert 			if (feof(stdin)) {
108496a888c6Smillert 				putchar('\n');
108596a888c6Smillert 				return(UINT_MAX - 1);
108696a888c6Smillert 			}
10876e0becc5Smillert 		}
10886fe57b42Smillert 		n = strlen(buf);
10896fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
10906fe57b42Smillert 			buf[--n] = '\0';
10916fe57b42Smillert 		if (buf[0] == '?')
10926fe57b42Smillert 			puts(helpstring);
10936fe57b42Smillert 	} while (buf[0] == '?');
10946fe57b42Smillert 
10956fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
10966fe57b42Smillert 		rval = maxval;
10976fe57b42Smillert 	} else {
10986fe57b42Smillert 		/* deal with units */
10996fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11006fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
110196a888c6Smillert 				switch (tolower(buf[n-1])) {
11026fe57b42Smillert 
11036fe57b42Smillert 				case 'c':
11046fe57b42Smillert 					mult = lp->d_secpercyl;
11056fe57b42Smillert 					buf[--n] = '\0';
11066fe57b42Smillert 					break;
11076fe57b42Smillert 				case 'b':
11086fe57b42Smillert 					mult = -lp->d_secsize;
11096fe57b42Smillert 					buf[--n] = '\0';
11106fe57b42Smillert 					break;
11116fe57b42Smillert 				case 'k':
11126fe57b42Smillert 					mult = 1024 / lp->d_secsize;
11136fe57b42Smillert 					buf[--n] = '\0';
11146fe57b42Smillert 					break;
11156fe57b42Smillert 				case 'm':
11166fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
11176fe57b42Smillert 					buf[--n] = '\0';
11186fe57b42Smillert 					break;
11191a51a1eeSmillert 				case 'g':
11201a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
11211a51a1eeSmillert 					buf[--n] = '\0';
11221a51a1eeSmillert 					break;
11236fe57b42Smillert 				}
112496a888c6Smillert 			}
11256fe57b42Smillert 
11266fe57b42Smillert 			/* Did they give us an operator? */
11276fe57b42Smillert 			p = &buf[0];
11286fe57b42Smillert 			if (*p == '+' || *p == '-')
11296fe57b42Smillert 				operator = *p++;
11306fe57b42Smillert 
11316fe57b42Smillert 			endptr = p;
113296a888c6Smillert 			errno = 0;
113396a888c6Smillert 			d = strtod(p, &endptr);
113496a888c6Smillert 			if (errno == ERANGE)
113596a888c6Smillert 				rval = UINT_MAX;	/* too big/small */
113696a888c6Smillert 			else if (*endptr != '\0') {
11376fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
11386fe57b42Smillert 				rval = UINT_MAX;
11396fe57b42Smillert 			} else {
114096a888c6Smillert 				/* XXX - should check for overflow */
114196a888c6Smillert 				if (mult > 0)
114296a888c6Smillert 					rval = d * mult;
114396a888c6Smillert 				else
114496a888c6Smillert 					/* Negative mult means divide (fancy) */
114596a888c6Smillert 					rval = d / (-mult);
11466fe57b42Smillert 
114796a888c6Smillert 				/* Apply the operator */
11486fe57b42Smillert 				if (operator == '+')
11496fe57b42Smillert 					rval += oval;
11506fe57b42Smillert 				else if (operator == '-')
11516fe57b42Smillert 					rval = oval - rval;
11526fe57b42Smillert 			}
11536fe57b42Smillert 		}
11546fe57b42Smillert 	}
11556fe57b42Smillert 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
1156dbffb156Smillert #ifndef CYLCHECK
115796a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
1158dbffb156Smillert 		if (mult != 1)
1159dbffb156Smillert #endif
1160dbffb156Smillert 		{
1161dbffb156Smillert 			u_int32_t cyls;
1162dbffb156Smillert 
1163dbffb156Smillert 			/* If we round up past the end, round down instead */
11646fe57b42Smillert 			cyls = (u_int32_t)((rval / (double)lp->d_secpercyl)
11656fe57b42Smillert 			    + 0.5);
11664b9a3bdaSmillert 			if (cyls != 0 && lp->d_secpercyl != 0) {
11674b9a3bdaSmillert 				if ((cyls * lp->d_secpercyl) - offset > maxval)
1168dbffb156Smillert 					cyls--;
1169dbffb156Smillert 
11704b9a3bdaSmillert 				if (rval != (cyls * lp->d_secpercyl) - offset) {
11714b9a3bdaSmillert 					rval = (cyls * lp->d_secpercyl) - offset;
11726fe57b42Smillert 					printf("Rounding to nearest cylinder: %u\n",
11736fe57b42Smillert 					    rval);
11746fe57b42Smillert 				}
11756fe57b42Smillert 			}
11766fe57b42Smillert 		}
11774b9a3bdaSmillert 	}
11786fe57b42Smillert 
11796fe57b42Smillert 	return(rval);
11806fe57b42Smillert }
11816fe57b42Smillert 
11826fe57b42Smillert /*
11836fe57b42Smillert  * Check for partition overlap in lp and prompt the user
11846fe57b42Smillert  * to resolve the overlap if any is found.  Returns 1
11856fe57b42Smillert  * if unable to resolve, else 0.
11866fe57b42Smillert  */
11876fe57b42Smillert int
11886fe57b42Smillert has_overlap(lp, freep, resolve)
11896fe57b42Smillert 	struct disklabel *lp;
11906fe57b42Smillert 	u_int32_t *freep;
11916fe57b42Smillert 	int resolve;
11926fe57b42Smillert {
11936fe57b42Smillert 	struct partition **spp;
11946fe57b42Smillert 	u_int16_t npartitions;
1195e6aa8bafSmillert 	int c, i, j;
1196e6aa8bafSmillert 	char buf[BUFSIZ];
11976fe57b42Smillert 
1198a7e61405Smillert 	/* Get a sorted list of the partitions */
1199a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
12006fe57b42Smillert 
1201a7e61405Smillert 	if (npartitions < 2) {
1202a7e61405Smillert 		(void)free(spp);
12036fe57b42Smillert 		return(0);			/* nothing to do */
12046fe57b42Smillert 	}
12056fe57b42Smillert 
12066fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12076fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
12086fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
12096fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
12106fe57b42Smillert 			if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) {
121196a888c6Smillert 				/* Don't print, just return */
121296a888c6Smillert 				if (resolve == -1) {
121396a888c6Smillert 					(void)free(spp);
121496a888c6Smillert 					return(1);
121596a888c6Smillert 				}
121696a888c6Smillert 
12176fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
12186fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
12196fe57b42Smillert 				    / sizeof(**spp);
12206fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
12216fe57b42Smillert 				    / sizeof(**spp);
12226fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
12236fe57b42Smillert 				    'a' + i, 'a' + j);
12246fe57b42Smillert 				puts("         size   offset    fstype   [fsize bsize   cpg]");
1225bd6726faSmillert 				display_partition(stdout, lp, NULL, i, 0, 0);
1226bd6726faSmillert 				display_partition(stdout, lp, NULL, j, 0, 0);
12276fe57b42Smillert 
12286fe57b42Smillert 				/* Did they ask us to resolve it ourselves? */
122996a888c6Smillert 				if (resolve != 1) {
1230f0b4d0a9Smillert 					(void)free(spp);
12316fe57b42Smillert 					return(1);
1232f0b4d0a9Smillert 				}
12336fe57b42Smillert 
1234e6aa8bafSmillert 				/* Get partition to disable or ^D */
1235e6aa8bafSmillert 				do {
1236616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
12376fe57b42Smillert 					    'a' + i, 'a' + j);
1238e6aa8bafSmillert 					buf[0] = '\0';
1239616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1240616cd1c4Smillert 						putchar('\n');
1241e6aa8bafSmillert 						return(1);	/* ^D */
1242616cd1c4Smillert 					}
1243e6aa8bafSmillert 					c = buf[0] - 'a';
1244e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1245e6aa8bafSmillert 				    c != i && c != j);
1246e6aa8bafSmillert 
1247e6aa8bafSmillert 				/* Mark the selected one as unused */
12486fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
12496fe57b42Smillert 				*freep += lp->d_partitions[c].p_size;
1250e6aa8bafSmillert 				(void)free(spp);
1251e6aa8bafSmillert 				return(has_overlap(lp, freep, resolve));
12526fe57b42Smillert 			}
12536fe57b42Smillert 		}
12546fe57b42Smillert 	}
1255f0b4d0a9Smillert 
1256f0b4d0a9Smillert 	(void)free(spp);
1257e6aa8bafSmillert 	return(0);
12586fe57b42Smillert }
12596fe57b42Smillert 
12606fe57b42Smillert void
12616fe57b42Smillert edit_parms(lp, freep)
12626fe57b42Smillert 	struct disklabel *lp;
12636fe57b42Smillert 	u_int32_t *freep;
12646fe57b42Smillert {
12656fe57b42Smillert 	char *p;
12666fe57b42Smillert 	u_int32_t ui;
126796a888c6Smillert 	struct disklabel oldlabel = *lp;
12686fe57b42Smillert 
1269ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
12706fe57b42Smillert 
12710f820bbbSmillert 	/* disk type */
12720f820bbbSmillert 	for (;;) {
12730f820bbbSmillert 		p = getstring(lp, "disk type",
127441282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
127541282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
127696a888c6Smillert 		if (p == NULL) {
127796a888c6Smillert 			fputs("Command aborted\n", stderr);
127896a888c6Smillert 			return;
127996a888c6Smillert 		}
128041282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
128141282a2aSmillert 			ui = DTYPE_ESDI;
128241282a2aSmillert 		else
128341282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
128441282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
12850f820bbbSmillert 				;
12860f820bbbSmillert 		if (ui < DKMAXTYPES) {
12870f820bbbSmillert 			break;
12880f820bbbSmillert 		} else {
12890f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
12900f820bbbSmillert 			fputs("Valid types are: ", stdout);
12910f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
12920f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
12930f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
12940f820bbbSmillert 					fputs(", ", stdout);
12950f820bbbSmillert 			}
12960f820bbbSmillert 			putchar('\n');
12970f820bbbSmillert 		}
12980f820bbbSmillert 	}
12990f820bbbSmillert 	lp->d_type = ui;
13000f820bbbSmillert 
13016fe57b42Smillert 	/* pack/label id */
13026fe57b42Smillert 	p = getstring(lp, "label name",
13036fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13046fe57b42Smillert 	    lp->d_packname);
130596a888c6Smillert 	if (p == NULL) {
130696a888c6Smillert 		fputs("Command aborted\n", stderr);
130796a888c6Smillert 		*lp = oldlabel;		/* undo damage */
130896a888c6Smillert 		return;
130996a888c6Smillert 	}
13106fe57b42Smillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1);
13116fe57b42Smillert 	lp->d_packname[sizeof(lp->d_packname) - 1] = '\0';
13126fe57b42Smillert 
13136fe57b42Smillert 	/* sectors/track */
13146fe57b42Smillert 	for (;;) {
13156fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
13166fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
13174b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
131896a888c6Smillert 		if (ui == UINT_MAX - 1) {
131996a888c6Smillert 			fputs("Command aborted\n", stderr);
132096a888c6Smillert 			*lp = oldlabel;		/* undo damage */
132196a888c6Smillert 			return;
132296a888c6Smillert 		} if (ui == UINT_MAX)
13236fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13246fe57b42Smillert 		else
13256fe57b42Smillert 			break;
13266fe57b42Smillert 	}
13276fe57b42Smillert 	lp->d_nsectors = ui;
13286fe57b42Smillert 
13296fe57b42Smillert 	/* tracks/cylinder */
13306fe57b42Smillert 	for (;;) {
13316fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
13326fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
13334b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
133496a888c6Smillert 		if (ui == UINT_MAX - 1) {
133596a888c6Smillert 			fputs("Command aborted\n", stderr);
133696a888c6Smillert 			*lp = oldlabel;		/* undo damage */
133796a888c6Smillert 			return;
133896a888c6Smillert 		} else if (ui == UINT_MAX)
13396fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13406fe57b42Smillert 		else
13416fe57b42Smillert 			break;
13426fe57b42Smillert 	}
13436fe57b42Smillert 	lp->d_ntracks = ui;
13446fe57b42Smillert 
13456fe57b42Smillert 	/* sectors/cylinder */
1346148b6188Smillert 	for (;;) {
1347148b6188Smillert 		ui = getuint(lp, 0, "sectors/cylinder",
1348148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
13494b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
13504b9a3bdaSmillert 		    0, 0);
135196a888c6Smillert 		if (ui == UINT_MAX - 1) {
135296a888c6Smillert 			fputs("Command aborted\n", stderr);
135396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
135496a888c6Smillert 			return;
135596a888c6Smillert 		} else if (ui == UINT_MAX)
1356148b6188Smillert 			fputs("Invalid entry\n", stderr);
1357148b6188Smillert 		else
1358148b6188Smillert 			break;
1359148b6188Smillert 	}
1360148b6188Smillert 	lp->d_secpercyl = ui;
13616fe57b42Smillert 
13626fe57b42Smillert 	/* number of cylinders */
13636fe57b42Smillert 	for (;;) {
13646fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
13656fe57b42Smillert 		    "The total number of cylinders on the disk.",
13664b9a3bdaSmillert 		    lp->d_ncylinders, lp->d_ncylinders, 0, 0);
136796a888c6Smillert 		if (ui == UINT_MAX - 1) {
136896a888c6Smillert 			fputs("Command aborted\n", stderr);
136996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
137096a888c6Smillert 			return;
137196a888c6Smillert 		} else if (ui == UINT_MAX)
13726fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13736fe57b42Smillert 		else
13746fe57b42Smillert 			break;
13756fe57b42Smillert 	}
13766fe57b42Smillert 	lp->d_ncylinders = ui;
13776fe57b42Smillert 
13786fe57b42Smillert 	/* total sectors */
13796fe57b42Smillert 	for (;;) {
13806fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
13816fe57b42Smillert 		    "The total number of sectors on the disk.",
13826fe57b42Smillert 		    lp->d_secperunit ? lp->d_secperunit :
13836fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders,
13844b9a3bdaSmillert 		    lp->d_ncylinders * lp->d_ncylinders, 0, 0);
138596a888c6Smillert 		if (ui == UINT_MAX - 1) {
138696a888c6Smillert 			fputs("Command aborted\n", stderr);
138796a888c6Smillert 			*lp = oldlabel;		/* undo damage */
138896a888c6Smillert 			return;
138996a888c6Smillert 		} else if (ui == UINT_MAX)
13906fe57b42Smillert 			fputs("Invalid entry\n", stderr);
139196a888c6Smillert 		else if (ui > lp->d_secperunit &&
139296a888c6Smillert 		    ending_sector == lp->d_secperunit) {
13936fe57b42Smillert 			/* grow free count */
13946fe57b42Smillert 			*freep += ui - lp->d_secperunit;
1395f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1396f98aebd4Smillert 			    "partition.");
13976fe57b42Smillert 			break;
139896a888c6Smillert 		} else if (ui < lp->d_secperunit &&
139996a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14006fe57b42Smillert 			/* shrink free count */
14016fe57b42Smillert 			if (lp->d_secperunit - ui > *freep)
14026fe57b42Smillert 				fprintf(stderr,
14036fe57b42Smillert 				    "Not enough free space to shrink by %u "
14046fe57b42Smillert 				    "sectors (only %u sectors left)\n",
14056fe57b42Smillert 				    lp->d_secperunit - ui, *freep);
14066fe57b42Smillert 			else {
14076fe57b42Smillert 				*freep -= lp->d_secperunit - ui;
14086fe57b42Smillert 				break;
14096fe57b42Smillert 			}
14106fe57b42Smillert 		} else
14116fe57b42Smillert 			break;
14126fe57b42Smillert 	}
141396a888c6Smillert 	/* Adjust ending_sector if necesary. */
141496a888c6Smillert 	if (ending_sector > ui)
141596a888c6Smillert 		ending_sector = ui;
14166fe57b42Smillert 	lp->d_secperunit = ui;
14176fe57b42Smillert 
14186fe57b42Smillert 	/* rpm */
14196fe57b42Smillert 	for (;;) {
14206fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1421a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
14224b9a3bdaSmillert 		  lp->d_rpm, lp->d_rpm, 0, 0);
142396a888c6Smillert 		if (ui == UINT_MAX - 1) {
142496a888c6Smillert 			fputs("Command aborted\n", stderr);
142596a888c6Smillert 			*lp = oldlabel;		/* undo damage */
142696a888c6Smillert 			return;
142796a888c6Smillert 		} else if (ui == UINT_MAX)
14286fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14296fe57b42Smillert 		else
14306fe57b42Smillert 			break;
14316fe57b42Smillert 	}
14326fe57b42Smillert 	lp->d_rpm = ui;
1433440b1d70Smillert 
1434440b1d70Smillert 	/* interleave */
1435440b1d70Smillert 	for (;;) {
1436440b1d70Smillert 		ui = getuint(lp, 0, "interleave",
1437440b1d70Smillert 		  "The physical sector interleave, set when formatting.  Almost always 1.",
14384b9a3bdaSmillert 		  lp->d_interleave, lp->d_interleave, 0, 0);
1439440b1d70Smillert 		if (ui == UINT_MAX - 1) {
1440440b1d70Smillert 			fputs("Command aborted\n", stderr);
1441440b1d70Smillert 			*lp = oldlabel;		/* undo damage */
1442440b1d70Smillert 			return;
1443440b1d70Smillert 		} else if (ui == UINT_MAX || ui == 0)
1444440b1d70Smillert 			fputs("Invalid entry\n", stderr);
1445440b1d70Smillert 		else
1446440b1d70Smillert 			break;
1447440b1d70Smillert 	}
1448440b1d70Smillert 	lp->d_interleave = ui;
14496fe57b42Smillert }
1450a7e61405Smillert 
1451a7e61405Smillert struct partition **
1452a7e61405Smillert sort_partitions(lp, npart)
1453a7e61405Smillert 	struct disklabel *lp;
1454a7e61405Smillert 	u_int16_t *npart;
1455a7e61405Smillert {
1456a7e61405Smillert 	u_int16_t npartitions;
1457a7e61405Smillert 	struct partition **spp;
1458a7e61405Smillert 	int i;
1459a7e61405Smillert 
1460a7e61405Smillert 	/* How many "real" partitions do we have? */
1461a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1462a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1463a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1464a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1465a7e61405Smillert 			npartitions++;
1466a7e61405Smillert 	}
146796a888c6Smillert 	if (npartitions == 0) {
146896a888c6Smillert 		*npart = 0;
146996a888c6Smillert 		return(NULL);
147096a888c6Smillert 	}
1471a7e61405Smillert 
1472a7e61405Smillert 	/* Create an array of pointers to the partition data */
1473a7e61405Smillert 	if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL)
1474a7e61405Smillert 		errx(4, "out of memory");
1475a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1476a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1477a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1478a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1479a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1480a7e61405Smillert 	}
1481a7e61405Smillert 
1482a7e61405Smillert 	/*
1483a7e61405Smillert 	 * Sort the partitions based on starting offset.
1484a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1485a7e61405Smillert 	 */
1486a7e61405Smillert 	if (npartitions > 1)
1487a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1488a7e61405Smillert 		    partition_cmp))
1489a7e61405Smillert 			err(4, "failed to sort partition table");
1490a7e61405Smillert 
1491a7e61405Smillert 	*npart = npartitions;
1492a7e61405Smillert 	return(spp);
1493a7e61405Smillert }
14940f820bbbSmillert 
14950f820bbbSmillert /*
14960f820bbbSmillert  * Get a valid disk type if necessary.
14970f820bbbSmillert  */
14980f820bbbSmillert void
1499803ff7d5Smillert getdisktype(lp, banner, dev)
15000f820bbbSmillert 	struct disklabel *lp;
15010f820bbbSmillert 	char *banner;
1502803ff7d5Smillert 	char *dev;
15030f820bbbSmillert {
15040f820bbbSmillert 	int i;
1505803ff7d5Smillert 	char *s, *def = "SCSI";
1506803ff7d5Smillert 	struct dtypes {
1507803ff7d5Smillert 		char *dev;
1508803ff7d5Smillert 		char *type;
1509803ff7d5Smillert 	} dtypes[] = {
1510803ff7d5Smillert 		"sd",	"SCSI",
1511508086e9Smillert 		"rz",	"SCSI",
1512803ff7d5Smillert 		"wd",	"IDE",
1513803ff7d5Smillert 		"fd",	"FLOPPY",
1514803ff7d5Smillert 		"xd",	"SMD",
1515803ff7d5Smillert 		"xy",	"SMD",
1516803ff7d5Smillert 		"hd",	"HP-IB",
1517803ff7d5Smillert 		"ccd",	"CCD",
1518803ff7d5Smillert 		"vnd",	"VND",
1519803ff7d5Smillert 		"svnd",	"VND",
1520803ff7d5Smillert 		NULL,	NULL
1521803ff7d5Smillert 	};
1522803ff7d5Smillert 
1523803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1524803ff7d5Smillert 		if (*s == 'r')
1525803ff7d5Smillert 			s++;
1526803ff7d5Smillert 		i = strcspn(s, "0123456789");
1527803ff7d5Smillert 		s[i] = '\0';
1528803ff7d5Smillert 		dev = s;
1529803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1530803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1531803ff7d5Smillert 				def = dtypes[i].type;
1532803ff7d5Smillert 				break;
1533803ff7d5Smillert 			}
1534803ff7d5Smillert 		}
1535803ff7d5Smillert 	}
15360f820bbbSmillert 
15370f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15380f820bbbSmillert 		puts(banner);
15390f820bbbSmillert 		puts("Possible values are:");
1540eb5dd924Sderaadt 		printf("\"IDE\", ");
15410f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15420f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15430f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15440f820bbbSmillert 				fputs(", ", stdout);
15450f820bbbSmillert 		}
15460f820bbbSmillert 		putchar('\n');
15470f820bbbSmillert 
15480f820bbbSmillert 		for (;;) {
15490f820bbbSmillert 			s = getstring(lp, "Disk type",
1550803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1551803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
155296a888c6Smillert 			if (s == NULL)
155396a888c6Smillert 				continue;
15545b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15555b412421Smillert 				lp->d_type = DTYPE_ESDI;
15565b412421Smillert 				return;
15575b412421Smillert 			}
15580f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15590f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15600f820bbbSmillert 					lp->d_type = i;
15610f820bbbSmillert 					return;
15620f820bbbSmillert 				}
15630f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15640f820bbbSmillert 			fputs("Valid types are: ", stdout);
15650f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15660f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15670f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15680f820bbbSmillert 					fputs(", ", stdout);
15690f820bbbSmillert 			}
15700f820bbbSmillert 			putchar('\n');
15710f820bbbSmillert 		}
15720f820bbbSmillert 	}
15730f820bbbSmillert }
157496a888c6Smillert 
157596a888c6Smillert /*
157696a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
157796a888c6Smillert  * from the user.
15784793b14cSmillert  * XXX - should mention MBR values if DOSLABEL
157996a888c6Smillert  */
158096a888c6Smillert void
1581e8e8bdb7Sart set_bounds(lp, freep)
158296a888c6Smillert 	struct disklabel *lp;
1583e8e8bdb7Sart 	u_int32_t *freep;
158496a888c6Smillert {
158596a888c6Smillert 	u_int32_t ui, start_temp;
158696a888c6Smillert 
158796a888c6Smillert 	/* Starting sector */
158896a888c6Smillert 	do {
158996a888c6Smillert 		ui = getuint(lp, 0, "Starting sector",
159096a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
15914b9a3bdaSmillert 		  starting_sector, lp->d_secperunit, 0, 0);
159296a888c6Smillert 		if (ui == UINT_MAX - 1) {
159396a888c6Smillert 			fputs("Command aborted\n", stderr);
159496a888c6Smillert 			return;
159596a888c6Smillert 		}
159696a888c6Smillert 	} while (ui >= lp->d_secperunit);
159796a888c6Smillert 	start_temp = ui;
159896a888c6Smillert 
15994793b14cSmillert 	/* Size */
160096a888c6Smillert 	do {
1601f98aebd4Smillert 		ui = getuint(lp, 0, "Size ('*' for entire disk)",
1602f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1603f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
16044b9a3bdaSmillert 		  lp->d_secperunit - start_temp, 0, 0);
160596a888c6Smillert 		if (ui == UINT_MAX - 1) {
160696a888c6Smillert 			fputs("Command aborted\n", stderr);
160796a888c6Smillert 			return;
160896a888c6Smillert 		}
1609f98aebd4Smillert 	} while (ui > lp->d_secperunit - start_temp);
16104793b14cSmillert 	ending_sector = start_temp + ui;
161196a888c6Smillert 	starting_sector = start_temp;
1612e8e8bdb7Sart 
1613e8e8bdb7Sart 	/* Recalculate the free sectors */
1614c0bdc608Smillert 	editor_countfree(lp, freep);
161596a888c6Smillert }
161696a888c6Smillert 
161796a888c6Smillert /*
161896a888c6Smillert  * Return a list of the "chunks" of free space available
161996a888c6Smillert  */
162096a888c6Smillert struct diskchunk *
162196a888c6Smillert free_chunks(lp)
162296a888c6Smillert 	struct disklabel *lp;
162396a888c6Smillert {
162496a888c6Smillert 	u_int16_t npartitions;
162596a888c6Smillert 	struct partition **spp;
162696a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
162796a888c6Smillert 	int i, numchunks;
162896a888c6Smillert 
162996a888c6Smillert 	/* Sort the partitions based on offset */
163096a888c6Smillert 	spp = sort_partitions(lp, &npartitions);
163196a888c6Smillert 
163296a888c6Smillert 	/* If there are no partitions, it's all free. */
163396a888c6Smillert 	if (spp == NULL) {
163496a888c6Smillert 		chunks[0].start = 0;
163596a888c6Smillert 		chunks[0].stop = ending_sector;
163696a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
163796a888c6Smillert 		return(chunks);
163896a888c6Smillert 	}
163996a888c6Smillert 
164096a888c6Smillert 	/* Find chunks of free space */
164196a888c6Smillert 	numchunks = 0;
164296a888c6Smillert 	if (spp && spp[0]->p_offset > 0) {
164396a888c6Smillert 		chunks[0].start = 0;
164496a888c6Smillert 		chunks[0].stop = spp[0]->p_offset;
164596a888c6Smillert 		numchunks++;
164696a888c6Smillert 	}
164796a888c6Smillert 	for (i = 0; i < npartitions; i++) {
164896a888c6Smillert 		if (i + 1 < npartitions) {
164996a888c6Smillert 			if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) {
165096a888c6Smillert 				chunks[numchunks].start =
165196a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
165296a888c6Smillert 				chunks[numchunks].stop = spp[i+1]->p_offset;
165396a888c6Smillert 				numchunks++;
165496a888c6Smillert 			}
165596a888c6Smillert 		} else {
165696a888c6Smillert 			/* Last partition */
165765ce672dScsapuntz 			if (spp[i]->p_offset + spp[i]->p_size < ending_sector) {
165896a888c6Smillert 
165996a888c6Smillert 				chunks[numchunks].start =
166096a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
166165ce672dScsapuntz 				chunks[numchunks].stop = ending_sector;
166296a888c6Smillert 				numchunks++;
166396a888c6Smillert 			}
166496a888c6Smillert 		}
166596a888c6Smillert 	}
166696a888c6Smillert 
166796a888c6Smillert 	/* Terminate and return */
166896a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
166996a888c6Smillert 	(void)free(spp);
167096a888c6Smillert 	return(chunks);
167196a888c6Smillert }
16724793b14cSmillert 
16734793b14cSmillert /*
16744793b14cSmillert  * What is the OpenBSD portion of the disk?  Uses the MBR if applicable.
16754793b14cSmillert  */
16764793b14cSmillert void
16774793b14cSmillert find_bounds(lp)
16784793b14cSmillert 	struct disklabel *lp;
16794793b14cSmillert {
1680f98aebd4Smillert 	struct partition *pp = &lp->d_partitions[2];
16814793b14cSmillert 
16824793b14cSmillert 	/* Defaults */
16834793b14cSmillert 	/* XXX - reserve a cylinder for hp300? */
16844793b14cSmillert 	starting_sector = 0;
16854793b14cSmillert 	ending_sector = lp->d_secperunit;
16864793b14cSmillert 
16874793b14cSmillert #ifdef DOSLABEL
1688*528915f5Smillert 	/*
1689*528915f5Smillert 	 * If we have an MBR, use values from the {Open,Free,Net}BSD partition.
1690*528915f5Smillert 	 */
1691aaa7b57dSderaadt 	if (dosdp && pp->p_size &&
1692aaa7b57dSderaadt 	    (dosdp->dp_typ == DOSPTYP_OPENBSD ||
1693aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_FREEBSD ||
1694aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_NETBSD)) {
1695*528915f5Smillert 		u_int32_t i, new_end;
1696*528915f5Smillert 
1697*528915f5Smillert 		/* Set start and end based on the fdisk partition bounds */
16984793b14cSmillert 		starting_sector = get_le(&dosdp->dp_start);
16994793b14cSmillert 		ending_sector = starting_sector + get_le(&dosdp->dp_size);
1700*528915f5Smillert 
1701*528915f5Smillert 		/*
1702*528915f5Smillert 		 * If there are any BSD or SWAP partitions beyond ending_sector
1703*528915f5Smillert 		 * we extend ending_sector to include them.  This is done
1704*528915f5Smillert 		 * because the BIOS geometry is generally different from the
1705*528915f5Smillert 		 * disk geometry.
1706*528915f5Smillert 		 */
1707*528915f5Smillert 		for (i = new_end = 0; i < lp->d_npartitions; i++) {
1708*528915f5Smillert 			pp = &lp->d_partitions[i];
1709*528915f5Smillert 			if ((pp->p_fstype == FS_BSDFFS ||
1710*528915f5Smillert 			    pp->p_fstype == FS_SWAP) &&
1711*528915f5Smillert 			    pp->p_size + pp->p_offset > new_end)
1712*528915f5Smillert 				new_end = pp->p_size + pp->p_offset;
1713*528915f5Smillert 		}
1714*528915f5Smillert 		if (new_end > ending_sector)
1715*528915f5Smillert 			ending_sector = new_end;
1716*528915f5Smillert 
1717508086e9Smillert 		printf("\nTreating sectors %u-%u as the OpenBSD portion of the "
17184793b14cSmillert 		    "disk.\nYou can use the 'b' command to change this.\n",
17194793b14cSmillert 		    starting_sector, ending_sector);
17204793b14cSmillert 	}
17214793b14cSmillert #endif
17224793b14cSmillert }
1723c0bdc608Smillert 
1724c0bdc608Smillert /*
1725c0bdc608Smillert  * Calculate free space.
1726c0bdc608Smillert  */
1727c0bdc608Smillert void
1728c0bdc608Smillert editor_countfree(lp, freep)
1729c0bdc608Smillert 	struct disklabel *lp;
1730c0bdc608Smillert 	u_int32_t *freep;
1731c0bdc608Smillert {
1732c0bdc608Smillert 	struct partition *pp;
1733c0bdc608Smillert 	int i;
1734c0bdc608Smillert 
1735c0bdc608Smillert 	*freep = ending_sector - starting_sector;
1736c0bdc608Smillert 	for (i = 0; i < lp->d_npartitions; i++) {
1737c0bdc608Smillert 		    pp = &lp->d_partitions[i];
1738c0bdc608Smillert 		    if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
1739c0bdc608Smillert 			pp->p_size > 0 &&
1740c0bdc608Smillert 			pp->p_offset + pp->p_size <= ending_sector &&
1741c0bdc608Smillert 			pp->p_offset >= starting_sector)
1742c0bdc608Smillert 			*freep -= pp->p_size;
1743c0bdc608Smillert 	}
1744c0bdc608Smillert }
1745617e6e4aSmillert 
1746617e6e4aSmillert void
1747617e6e4aSmillert editor_help(arg)
1748617e6e4aSmillert 	char *arg;
1749617e6e4aSmillert {
1750617e6e4aSmillert 
1751617e6e4aSmillert 	/* XXX - put these strings in a table instead? */
1752617e6e4aSmillert 	switch (*arg) {
1753617e6e4aSmillert 	case 'p':
1754617e6e4aSmillert 		puts(
1755617e6e4aSmillert "The 'p' command prints the current disk label.  By default, it prints the\n"
1756617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1757617e6e4aSmillert "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1758617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1759617e6e4aSmillert 		break;
1760617e6e4aSmillert 	case 'M':
1761617e6e4aSmillert 		puts(
1762617e6e4aSmillert "The 'M' command pipes the entire OpenBSD manual page for disklabel though\n"
1763508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n"
1764508086e9Smillert "not set.  It is especially useful during install when the normal system\n"
1765508086e9Smillert "manual is not available.\n");
1766617e6e4aSmillert 		break;
1767617e6e4aSmillert 	case 'e':
1768617e6e4aSmillert 		puts(
1769617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters.  These include\n"
1770617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n"
1771617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n"
1772617e6e4aSmillert "type, and a descriptive label string.  You should not change these unless\n"
1773617e6e4aSmillert "you know what you are doing\n");
1774617e6e4aSmillert 		break;
1775617e6e4aSmillert 	case 'a':
1776617e6e4aSmillert 		puts(
1777617e6e4aSmillert "The 'a' command adds new partitions to the disk.  It takes as an optional\n"
1778617e6e4aSmillert "argument the partition letter to add.  If you do not specify a partition\n"
1779617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n"
1780617e6e4aSmillert "default answer\n");
1781617e6e4aSmillert 		break;
1782617e6e4aSmillert 	case 'b':
1783617e6e4aSmillert 		puts(
1784617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n"
1785617e6e4aSmillert "the disk.  This is only useful on disks with an fdisk partition.  By default,\n"
1786617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n"
1787617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition.  You should only change\n"
1788617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n"
1789617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be.  You\n"
1790617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n"
1791617e6e4aSmillert "(minus the starting sector).  Use this option with care; if you extend the\n"
1792617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n"
1793617e6e4aSmillert "corrupt the other operating system's data.\n");
1794617e6e4aSmillert 		break;
1795617e6e4aSmillert 	case 'c':
1796617e6e4aSmillert 		puts(
1797617e6e4aSmillert "The 'c' command is used to change the size of an existing partition.  It\n"
1798617e6e4aSmillert "takes as an optional argument the partition letter to change.  If you do not\n"
1799617e6e4aSmillert "specify a partition letter, you will be prompted for one.  You may add a '+'\n"
1800617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n"
1801617e6e4aSmillert "instead of entering an absolute value.  You may also use a suffix to indicate\n"
1802617e6e4aSmillert "the units the values is in terms of.  Possible suffixes are 'b' for bytes,\n"
1803617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n"
1804617e6e4aSmillert "no suffix for sectors (usually 512 bytes).  You may also enter '*' to change\n"
1805617e6e4aSmillert "the size to be the total number of free sectors remaining.\n");
1806617e6e4aSmillert 		break;
1807617e6e4aSmillert 	case 'd':
1808617e6e4aSmillert 		puts(
1809617e6e4aSmillert "The 'd' command is used to delete an existing partition.  It takes as an\n"
1810617e6e4aSmillert "optional argument the partition letter to change.  If you do not specify a\n"
1811617e6e4aSmillert "partition letter, you will be prompted for one.  You may not delete the ``c''\n"
1812617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n"
1813617e6e4aSmillert "it does not take up any space).\n");
1814617e6e4aSmillert 		break;
1815617e6e4aSmillert 	case 'm':
1816617e6e4aSmillert 		puts(
1817617e6e4aSmillert "The 'm' command is used to modify an existing partition.  It takes as an\n"    "optional argument the partition letter to change.  If you do not specify a\n"
1818617e6e4aSmillert "partition letter, you will be prompted for one.  This option allows the user\n"
1819617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n"
1820617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n"
1821617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n");
1822617e6e4aSmillert 		break;
1823bd6726faSmillert 	case 'n':
1824bd6726faSmillert 		puts(
1825bd6726faSmillert "The 'm' command is used to set the mount point for a partition (ie: name it).\n"
1826bd6726faSmillert "It takes as an optional argument the partition letter to name.  If you do\n"
1827bd6726faSmillert "not specify a partition letter, you will be prompted for one.  This option\n"
1828bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n");
1829bd6726faSmillert 		break;
1830617e6e4aSmillert 	case 'r':
1831617e6e4aSmillert 		puts(
1832617e6e4aSmillert "The 'r' command is used to recalculate the free space available.  This option\n"
1833617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n"
1834617e6e4aSmillert "disklabel gets confused.\n");
1835617e6e4aSmillert 		break;
1836617e6e4aSmillert 	case 'u':
1837617e6e4aSmillert 		puts(
1838617e6e4aSmillert "The 'u' command will undo (or redo) the last change.  Entering 'u' once will\n"
1839617e6e4aSmillert "undo your last change.  Entering it again will restore the change.\n");
1840617e6e4aSmillert 		break;
1841617e6e4aSmillert 	case 's':
1842617e6e4aSmillert 		puts(
1843617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n"
1844617e6e4aSmillert "(suitable for loading via disklabel's [-R] option).  It takes as an optional\n"
1845617e6e4aSmillert "argument the filename to save the label to.  If you do not specify a filename,\n"
1846617e6e4aSmillert "you will be prompted for one.\n");
1847617e6e4aSmillert 		break;
1848617e6e4aSmillert 	case 'w':
1849617e6e4aSmillert 		puts(
1850617e6e4aSmillert "The 'w' command will write the current label to disk.  This option will\n"
1851617e6e4aSmillert "commit any changes to the on-disk label.\n");
1852617e6e4aSmillert 		break;
1853617e6e4aSmillert 	case 'q':
1854617e6e4aSmillert 		puts(
1855617e6e4aSmillert "The 'q' command quits the label editor.  If any changes have been made you\n"
1856617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n");
1857617e6e4aSmillert 		break;
1858617e6e4aSmillert 	case 'x':
1859617e6e4aSmillert 		puts(
1860617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n"
1861617e6e4aSmillert "on-disk label.\n");
1862617e6e4aSmillert 		break;
1863617e6e4aSmillert 	default:
1864617e6e4aSmillert 		puts("Available commands:");
1865617e6e4aSmillert 		puts("\tp [unit]  - print label.");
1866617e6e4aSmillert 		puts("\tM         - show entire OpenBSD man page for disklabel.");
1867617e6e4aSmillert 		puts("\te         - edit drive parameters.");
1868617e6e4aSmillert 		puts("\ta [part]  - add new partition.");
1869617e6e4aSmillert 		puts("\tb         - set OpenBSD disk boundaries.");
1870617e6e4aSmillert 		puts("\tc [part]  - change partition size.");
1871617e6e4aSmillert 		puts("\td [part]  - delete partition.");
1872617e6e4aSmillert 		puts("\tm [part]  - modify existing partition.");
1873bd6726faSmillert 		puts("\tn [part]  - set the mount point for a partition.");
1874617e6e4aSmillert 		puts("\tr         - recalculate free space.");
1875617e6e4aSmillert 		puts("\tu         - undo last change.");
1876617e6e4aSmillert 		puts("\ts [path]  - save label to file.");
1877617e6e4aSmillert 		puts("\tw         - write label to disk.");
1878617e6e4aSmillert 		puts("\tq         - quit and save changes.");
1879617e6e4aSmillert 		puts("\tx         - exit without saving changes.");
1880617e6e4aSmillert 		puts("\t? [cmnd]  - this message or command specific help.");
1881617e6e4aSmillert 		puts(
1882617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t"
1883617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t"
1884617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t"
1885617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n"
1886617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help.");
1887617e6e4aSmillert 		break;
1888617e6e4aSmillert 	}
1889617e6e4aSmillert }
1890bd6726faSmillert 
1891bd6726faSmillert char **
1892bd6726faSmillert mpcopy(to, from)
1893bd6726faSmillert 	char **to;
1894bd6726faSmillert 	char **from;
1895bd6726faSmillert {
1896bd6726faSmillert 	int i;
1897bd6726faSmillert 
1898bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1899bd6726faSmillert 		if (from[i] != NULL) {
1900bd6726faSmillert 			to[i] = realloc(to[i], strlen(from[i]) + 1);
1901bd6726faSmillert 			if (to[i] == NULL)
1902bd6726faSmillert 				errx(4, "out of memory");
1903bd6726faSmillert 			(void)strcpy(to[i], from[i]);
1904bd6726faSmillert 		} else if (to[i] != NULL) {
1905bd6726faSmillert 			free(to[i]);
1906bd6726faSmillert 			to[i] = NULL;
1907bd6726faSmillert 		}
1908bd6726faSmillert 	}
1909bd6726faSmillert 	return(to);
1910bd6726faSmillert }
1911bd6726faSmillert 
1912bd6726faSmillert int
1913bd6726faSmillert mpequal(mp1, mp2)
1914bd6726faSmillert 	char **mp1;
1915bd6726faSmillert 	char **mp2;
1916bd6726faSmillert {
1917bd6726faSmillert 	int i;
1918bd6726faSmillert 
1919bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1920bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1921bd6726faSmillert 			continue;
1922bd6726faSmillert 
1923bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1924bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1925bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1926bd6726faSmillert 			return(0);
1927bd6726faSmillert 	}
1928bd6726faSmillert 	return(1);
1929bd6726faSmillert }
1930bd6726faSmillert 
1931bd6726faSmillert int
1932bd6726faSmillert mpsave(lp, mp, cdev, fstabfile)
1933bd6726faSmillert 	struct disklabel *lp;
1934bd6726faSmillert 	char **mp;
1935bd6726faSmillert 	char *cdev;
1936bd6726faSmillert 	char *fstabfile;
1937bd6726faSmillert {
1938bd6726faSmillert 	int i, mpset;
1939bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
19403f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1941bd6726faSmillert 	FILE *fp;
1942bd6726faSmillert 
19433f843443Smillert 	memset(&mi, 0, sizeof(mi));
19443f843443Smillert 
1945bd6726faSmillert 	for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) {
1946bd6726faSmillert 		if (mp[i] != NULL) {
19473f843443Smillert 			mi[i].mountpoint = mp[i];
19483f843443Smillert 			mi[i].partno = i;
1949bd6726faSmillert 			mpset = 1;
1950bd6726faSmillert 		}
1951bd6726faSmillert 	}
19523f843443Smillert 	/* Exit if there is nothing to do... */
1953bd6726faSmillert 	if (!mpset)
19543f843443Smillert 		return(0);
1955bd6726faSmillert 
1956bd6726faSmillert 	/* Convert cdev to bdev */
1957bd6726faSmillert 	if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 &&
1958bd6726faSmillert 	    cdev[sizeof(_PATH_DEV) - 1] == 'r') {
1959bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
1960bd6726faSmillert 		    &cdev[sizeof(_PATH_DEV)]);
1961bd6726faSmillert 	} else {
1962bd6726faSmillert 		if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r')
1963bd6726faSmillert 			return(1);
1964bd6726faSmillert 		*p = '\0';
1965bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1);
1966bd6726faSmillert 		*p = 'r';
1967bd6726faSmillert 	}
1968bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1969bd6726faSmillert 
19703f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
19713f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
19723f843443Smillert 
1973bd6726faSmillert 	if ((fp = fopen(fstabfile, "w")) == NULL)
1974bd6726faSmillert 		return(1);
1975bd6726faSmillert 
19763f843443Smillert 	for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) {
19773f843443Smillert 		fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + mi[i].partno,
19783f843443Smillert 		    mi[i].mountpoint,
1979bd6726faSmillert 		    fstypesnames[lp->d_partitions[i].p_fstype],
1980bd6726faSmillert 		    i == 0 ? 1 : 2);
1981bd6726faSmillert 	}
1982bd6726faSmillert 	fclose(fp);
1983bd6726faSmillert 	printf("Wrote fstab entries to %s\n", fstabfile);
1984bd6726faSmillert 	return(0);
1985bd6726faSmillert }
198624a2c1a4Smillert 
198724a2c1a4Smillert int
198824a2c1a4Smillert get_offset(lp, partno)
198924a2c1a4Smillert 	struct disklabel *lp;
199024a2c1a4Smillert 	int partno;
199124a2c1a4Smillert {
199224a2c1a4Smillert 	u_int32_t ui;
199324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
199424a2c1a4Smillert 
199524a2c1a4Smillert 	for (;;) {
199624a2c1a4Smillert 		ui = getuint(lp, partno, "offset",
199724a2c1a4Smillert 		   "Starting sector for this partition.", pp->p_offset,
199824a2c1a4Smillert 		   pp->p_offset, 0, DO_CONVERSIONS |
199924a2c1a4Smillert 		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
200024a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
200124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
200224a2c1a4Smillert 			return(1);
200324a2c1a4Smillert 		} else if (ui == UINT_MAX)
200424a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
200524a2c1a4Smillert 		else if (ui < starting_sector)
200624a2c1a4Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
200724a2c1a4Smillert 			    " at sector %u, you tried to add a partition at %u."
200824a2c1a4Smillert 			    "  You can use the 'b' command to change the size "
200924a2c1a4Smillert 			    "of the OpenBSD portion.\n" , starting_sector, ui);
201024a2c1a4Smillert 		else if (ui >= ending_sector)
201124a2c1a4Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
201224a2c1a4Smillert 			    "at sector %u, you tried to add a partition at %u."
201324a2c1a4Smillert 			    "  You can use the 'b' command to change the size "
201424a2c1a4Smillert 			    "of the OpenBSD portion.\n", ending_sector, ui);
201524a2c1a4Smillert 		else
201624a2c1a4Smillert 			break;
201724a2c1a4Smillert 	}
201824a2c1a4Smillert 	pp->p_offset = ui;
201924a2c1a4Smillert 	return(0);
202024a2c1a4Smillert }
202124a2c1a4Smillert 
202224a2c1a4Smillert int
202324a2c1a4Smillert get_size(lp, partno, freep, new)
202424a2c1a4Smillert 	struct disklabel *lp;
202524a2c1a4Smillert 	int partno;
202624a2c1a4Smillert 	u_int32_t *freep;
202724a2c1a4Smillert 	int new;
202824a2c1a4Smillert {
202924a2c1a4Smillert 	u_int32_t ui;
203024a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
203124a2c1a4Smillert 
203224a2c1a4Smillert 	for (;;) {
203324a2c1a4Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
203424a2c1a4Smillert 		    pp->p_size, *freep, pp->p_offset, DO_CONVERSIONS |
203524a2c1a4Smillert 		    ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ?
203624a2c1a4Smillert 		    DO_ROUNDING : 0));
203724a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
203824a2c1a4Smillert 			fputs("Command aborted\n", stderr);
203924a2c1a4Smillert 			return(1);
204024a2c1a4Smillert 		} else if (ui == UINT_MAX) {
204124a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
204224a2c1a4Smillert 			continue;
204324a2c1a4Smillert 		}
204424a2c1a4Smillert 		if (new) {
204524a2c1a4Smillert 			if (ui > *freep)
204624a2c1a4Smillert 				/* XXX - steal space from another partition */
204724a2c1a4Smillert 				fprintf(stderr,"Sorry, there are only %u "
204824a2c1a4Smillert 				    "sectors left\n", *freep);
204924a2c1a4Smillert 			else if (pp->p_offset + ui > ending_sector)
205024a2c1a4Smillert 				fprintf(stderr, "The OpenBSD portion of the "
205124a2c1a4Smillert 				    "disk ends at sector %u, you tried to add "
205224a2c1a4Smillert 				    "a partition ending at sector %u.  You can "
205324a2c1a4Smillert 				    "use the 'b' command to change the size of "
205424a2c1a4Smillert 				    "the OpenBSD portion.\n",
205524a2c1a4Smillert 				    ending_sector, pp->p_offset + ui);
205624a2c1a4Smillert 			else
205724a2c1a4Smillert 				break;			/* ok */
205824a2c1a4Smillert 		} else {
205924a2c1a4Smillert 			if (ui == pp->p_size)
206024a2c1a4Smillert 				break;			/* no change */
206124a2c1a4Smillert 			if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) {
206224a2c1a4Smillert 				fputs("'c' partition may not be larger than the disk\n",
206324a2c1a4Smillert 				    stderr);
206424a2c1a4Smillert 			} else if (pp->p_fstype == FS_UNUSED ||
206524a2c1a4Smillert 			    pp->p_fstype == FS_BOOT) {
206624a2c1a4Smillert 				/* don't care what's free */
206724a2c1a4Smillert 				pp->p_size = ui;
206824a2c1a4Smillert 				break;
206924a2c1a4Smillert 			} else {
207024a2c1a4Smillert 				if (ui > pp->p_size + *freep)
207124a2c1a4Smillert 					/* XXX - steal from another partition */
207224a2c1a4Smillert 					fprintf(stderr,
207324a2c1a4Smillert 					    "Size may not be larger than %u "
207424a2c1a4Smillert 					    "sectors\n", pp->p_size + *freep);
207524a2c1a4Smillert 				else {
207624a2c1a4Smillert 					*freep += pp->p_size - ui;
207724a2c1a4Smillert 					pp->p_size = ui;
207824a2c1a4Smillert 					break;			/* ok */
207924a2c1a4Smillert 				}
208024a2c1a4Smillert 			}
208124a2c1a4Smillert 		}
208224a2c1a4Smillert 	}
208324a2c1a4Smillert 	pp->p_size = ui;
208424a2c1a4Smillert 	return(0);
208524a2c1a4Smillert }
208624a2c1a4Smillert 
208724a2c1a4Smillert int
208824a2c1a4Smillert get_fsize(lp, partno)
208924a2c1a4Smillert 	struct disklabel *lp;
209024a2c1a4Smillert 	int partno;
209124a2c1a4Smillert {
209224a2c1a4Smillert 	u_int32_t ui;
209324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
209424a2c1a4Smillert 
209524a2c1a4Smillert 	for (;;) {
209624a2c1a4Smillert 		ui = getuint(lp, partno, "fragment size",
209724a2c1a4Smillert 		    "Size of fs block fragments.  Usually 1024 or 512.",
209824a2c1a4Smillert 		    pp->p_fsize, pp->p_fsize, 0, 0);
209924a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
210024a2c1a4Smillert 			fputs("Command aborted\n", stderr);
210124a2c1a4Smillert 			return(1);
210224a2c1a4Smillert 		} else if (ui == UINT_MAX)
210324a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
210424a2c1a4Smillert 		else
210524a2c1a4Smillert 			break;
210624a2c1a4Smillert 	}
210724a2c1a4Smillert 	if (ui == 0)
210824a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
210924a2c1a4Smillert 	pp->p_fsize = ui;
211024a2c1a4Smillert 	return(0);
211124a2c1a4Smillert }
211224a2c1a4Smillert 
211324a2c1a4Smillert int
211424a2c1a4Smillert get_bsize(lp, partno)
211524a2c1a4Smillert 	struct disklabel *lp;
211624a2c1a4Smillert 	int partno;
211724a2c1a4Smillert {
211824a2c1a4Smillert 	u_int32_t ui;
211924a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
212024a2c1a4Smillert 
212124a2c1a4Smillert 	/* Avoid dividing by zero... */
212224a2c1a4Smillert 	if (pp->p_fsize == 0) {
212324a2c1a4Smillert 		pp->p_frag = 0;
212424a2c1a4Smillert 		return(1);
212524a2c1a4Smillert 	}
212624a2c1a4Smillert 
212724a2c1a4Smillert 	for (;;) {
212824a2c1a4Smillert 		ui = getuint(lp, partno, "block size",
212924a2c1a4Smillert 		    "Size of filesystem blocks.  Usually 8192 or 4096.",
213024a2c1a4Smillert 		    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
213124a2c1a4Smillert 		    0, 0);
213224a2c1a4Smillert 
213324a2c1a4Smillert 		/* sanity checks */
213424a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
213524a2c1a4Smillert 			fputs("Command aborted\n", stderr);
213624a2c1a4Smillert 			return(1);
213724a2c1a4Smillert 		} else if (ui == UINT_MAX)
213824a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
213924a2c1a4Smillert 		else if (ui < getpagesize())
214024a2c1a4Smillert 			fprintf(stderr,
214124a2c1a4Smillert 			    "Error: block size must be at least as big "
214224a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
214324a2c1a4Smillert 		else if (ui % pp->p_fsize != 0)
214424a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
214524a2c1a4Smillert 			    "fragment size.\n", stderr);
214624a2c1a4Smillert 		else if (ui / pp->p_fsize < 1)
214724a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
214824a2c1a4Smillert 			    "fragment size.\n", stderr);
214924a2c1a4Smillert 		else
215024a2c1a4Smillert 			break;
215124a2c1a4Smillert 	}
215224a2c1a4Smillert 	pp->p_frag = ui / pp->p_fsize;
215324a2c1a4Smillert 	return(0);
215424a2c1a4Smillert }
215524a2c1a4Smillert 
215624a2c1a4Smillert int
215724a2c1a4Smillert get_cpg(lp, partno)
215824a2c1a4Smillert 	struct disklabel *lp;
215924a2c1a4Smillert 	int partno;
216024a2c1a4Smillert {
216124a2c1a4Smillert 	u_int32_t ui;
216224a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
216324a2c1a4Smillert 
216424a2c1a4Smillert 	for (;;) {
216524a2c1a4Smillert 		ui = getuint(lp, partno, "cpg",
216624a2c1a4Smillert 		    "Number of filesystem cylinders per group."
216724a2c1a4Smillert 		    "  Usually 16 or 8.",
216824a2c1a4Smillert 		    pp->p_cpg ? pp->p_cpg : 16, 16, 0, 0);
216924a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
217024a2c1a4Smillert 			fputs("Command aborted\n", stderr);
217124a2c1a4Smillert 			return(1);
217224a2c1a4Smillert 		} else if (ui == UINT_MAX)
217324a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
217424a2c1a4Smillert 		else
217524a2c1a4Smillert 			break;
217624a2c1a4Smillert 	}
217724a2c1a4Smillert 	pp->p_cpg = ui;
217824a2c1a4Smillert 	return(0);
217924a2c1a4Smillert }
218024a2c1a4Smillert 
218124a2c1a4Smillert int
218224a2c1a4Smillert get_fstype(lp, partno)
218324a2c1a4Smillert 	struct disklabel *lp;
218424a2c1a4Smillert 	int partno;
218524a2c1a4Smillert {
218624a2c1a4Smillert 	char *p;
218724a2c1a4Smillert 	u_int32_t ui;
218824a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
218924a2c1a4Smillert 
219024a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
219124a2c1a4Smillert 		p = getstring(lp, "FS type",
219224a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
219324a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
219424a2c1a4Smillert 		if (p == NULL) {
219524a2c1a4Smillert 			fputs("Command aborted\n", stderr);
219624a2c1a4Smillert 			return(1);
219724a2c1a4Smillert 		}
219824a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
219924a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
220024a2c1a4Smillert 				pp->p_fstype = ui;
220124a2c1a4Smillert 				break;
220224a2c1a4Smillert 			}
220324a2c1a4Smillert 		}
220424a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
220524a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
220624a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
220724a2c1a4Smillert 		}
220824a2c1a4Smillert 	} else {
220924a2c1a4Smillert 		for (;;) {
221024a2c1a4Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
221124a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
221224a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
221324a2c1a4Smillert 			if (ui == UINT_MAX - 1) {
221424a2c1a4Smillert 				fputs("Command aborted\n", stderr);
221524a2c1a4Smillert 				return(1);
221624a2c1a4Smillert 			} if (ui == UINT_MAX)
221724a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
221824a2c1a4Smillert 			else
221924a2c1a4Smillert 				break;
222024a2c1a4Smillert 		}
222124a2c1a4Smillert 		pp->p_fstype = ui;
222224a2c1a4Smillert 	}
222324a2c1a4Smillert 	return(0);
222424a2c1a4Smillert }
222524a2c1a4Smillert 
222624a2c1a4Smillert int
222724a2c1a4Smillert get_mp(lp, mp, partno)
222824a2c1a4Smillert 	struct disklabel *lp;
222924a2c1a4Smillert 	char **mp;
223024a2c1a4Smillert 	int partno;
223124a2c1a4Smillert {
223224a2c1a4Smillert 	char *p;
223324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
223424a2c1a4Smillert 
223524a2c1a4Smillert 	if (mp != NULL && pp->p_fstype != FS_UNUSED &&
223624a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
223724a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
2238ddaff619Smillert 		for (;;) {
223924a2c1a4Smillert 			p = getstring(lp, "mount point",
224024a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
224124a2c1a4Smillert 			    mp[partno] ? mp[partno] : "none");
224224a2c1a4Smillert 			if (p == NULL) {
224324a2c1a4Smillert 				fputs("Command aborted\n", stderr);
224424a2c1a4Smillert 				return(1);
224524a2c1a4Smillert 			}
2246ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
224724a2c1a4Smillert 				if (mp[partno] != NULL) {
224824a2c1a4Smillert 					free(mp[partno]);
224924a2c1a4Smillert 					mp[partno] = NULL;
225024a2c1a4Smillert 				}
2251ddaff619Smillert 				break;
2252ddaff619Smillert 			}
2253ddaff619Smillert 			if (*p == '/') {
2254ddaff619Smillert 				/* XXX - might as well realloc */
2255ddaff619Smillert 				if (mp[partno] != NULL)
2256ddaff619Smillert 					free(mp[partno]);
225724a2c1a4Smillert 				if ((mp[partno] = strdup(p)) == NULL)
225824a2c1a4Smillert 					errx(4, "out of memory");
2259ddaff619Smillert 				break;
2260ddaff619Smillert 			}
2261ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
226224a2c1a4Smillert 		}
226324a2c1a4Smillert 	}
226424a2c1a4Smillert 	return(0);
226524a2c1a4Smillert }
22663f843443Smillert 
22673f843443Smillert int
22683f843443Smillert micmp(a1, a2)
22693f843443Smillert 	const void *a1;
22703f843443Smillert 	const void *a2;
22713f843443Smillert {
22723f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
22733f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
22743f843443Smillert 
22753f843443Smillert 	/* We want all the NULLs at the end... */
22763f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
22773f843443Smillert 		return(0);
22783f843443Smillert 	else if (mi1->mountpoint == NULL)
22793f843443Smillert 		return(1);
22803f843443Smillert 	else if (mi2->mountpoint == NULL)
22813f843443Smillert 		return(-1);
22823f843443Smillert 	else
22833f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
22843f843443Smillert }
2285