xref: /openbsd/sbin/disklabel/editor.c (revision cdd7eb76)
1*cdd7eb76Smillert /*	$OpenBSD: editor.c,v 1.72 2000/06/04 18:34:41 millert Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
42d8451b0Smillert  * Copyright (c) 1997-2000 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*cdd7eb76Smillert static char rcsid[] = "$OpenBSD: editor.c,v 1.72 2000/06/04 18:34:41 millert Exp $";
326fe57b42Smillert #endif /* not lint */
336fe57b42Smillert 
346fe57b42Smillert #include <sys/types.h>
356fe57b42Smillert #include <sys/param.h>
36c33fcabaSmillert #include <sys/stat.h>
37c33fcabaSmillert #include <sys/ioctl.h>
386fe57b42Smillert #define	DKTYPENAMES
396fe57b42Smillert #include <sys/disklabel.h>
40c33fcabaSmillert #include <sys/reboot.h>
41c33fcabaSmillert #include <sys/sysctl.h>
42c33fcabaSmillert #include <machine/cpu.h>
43c33fcabaSmillert #ifdef CPU_BIOS
44c33fcabaSmillert #include <machine/biosvar.h>
45c33fcabaSmillert #endif
466fe57b42Smillert 
476fe57b42Smillert #include <ufs/ffs/fs.h>
486fe57b42Smillert 
496fe57b42Smillert #include <ctype.h>
506fe57b42Smillert #include <err.h>
516fe57b42Smillert #include <errno.h>
526fe57b42Smillert #include <string.h>
53803ff7d5Smillert #include <libgen.h>
546fe57b42Smillert #include <stdio.h>
556fe57b42Smillert #include <stdlib.h>
566fe57b42Smillert #include <unistd.h>
576fe57b42Smillert 
584793b14cSmillert #include "pathnames.h"
594793b14cSmillert 
606fe57b42Smillert /* flags for getuint() */
616fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
626fe57b42Smillert #define	DO_ROUNDING	0x00000002
636fe57b42Smillert 
64f98aebd4Smillert #ifndef NUMBOOT
65f98aebd4Smillert #define NUMBOOT 0
66f98aebd4Smillert #endif
67f98aebd4Smillert 
6896a888c6Smillert /* structure to describe a portion of a disk */
6996a888c6Smillert struct diskchunk {
7096a888c6Smillert 	u_int32_t start;
7196a888c6Smillert 	u_int32_t stop;
7296a888c6Smillert };
7396a888c6Smillert 
743f843443Smillert /* used when sorting mountpoints in mpsave() */
753f843443Smillert struct mountinfo {
763f843443Smillert 	char *mountpoint;
773f843443Smillert 	int partno;
783f843443Smillert };
793f843443Smillert 
806fe57b42Smillert void	edit_parms __P((struct disklabel *, u_int32_t *));
819785f718Smillert int	editor __P((struct disklabel *, int, char *, char *));
82bd6726faSmillert void	editor_add __P((struct disklabel *, char **, u_int32_t *, char *));
836fe57b42Smillert void	editor_change __P((struct disklabel *, u_int32_t *, char *));
84c0bdc608Smillert void	editor_countfree __P((struct disklabel *, u_int32_t *));
85bd6726faSmillert void	editor_delete __P((struct disklabel *, char **, u_int32_t *, char *));
86bd6726faSmillert void	editor_display __P((struct disklabel *, char **, u_int32_t *, char));
87617e6e4aSmillert void	editor_help __P((char *));
88bd6726faSmillert void	editor_modify __P((struct disklabel *, char **, u_int32_t *, char *));
89bd6726faSmillert void	editor_name __P((struct disklabel *, char **, char *));
90c33fcabaSmillert char	*getstring __P((char *, char *, char *));
914b9a3bdaSmillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, u_int32_t, int));
926fe57b42Smillert int	has_overlap __P((struct disklabel *, u_int32_t *, int));
936fe57b42Smillert void	make_contiguous __P((struct disklabel *));
942d8451b0Smillert u_int32_t next_offset __P((struct disklabel *, u_int32_t *));
956fe57b42Smillert int	partition_cmp __P((const void *, const void *));
96a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));
97803ff7d5Smillert void	getdisktype __P((struct disklabel *, char *, char *));
989785f718Smillert void	find_bounds __P((struct disklabel *, struct disklabel *));
99e8e8bdb7Sart void	set_bounds __P((struct disklabel *, u_int32_t *));
10096a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *));
101bd6726faSmillert char **	mpcopy __P((char **, char **));
1023f843443Smillert int	micmp __P((const void *, const void *));
103bd6726faSmillert int	mpequal __P((char **, char **));
104bd6726faSmillert int	mpsave __P((struct disklabel *, char **, char *, char *));
10524a2c1a4Smillert int	get_bsize __P((struct disklabel *, int));
10624a2c1a4Smillert int	get_cpg __P((struct disklabel *, int));
10724a2c1a4Smillert int	get_fsize __P((struct disklabel *, int));
10824a2c1a4Smillert int	get_fstype __P((struct disklabel *, int));
10924a2c1a4Smillert int	get_mp __P((struct disklabel *, char **, int));
11024a2c1a4Smillert int	get_offset __P((struct disklabel *, int));
11124a2c1a4Smillert int	get_size __P((struct disklabel *, int, u_int32_t *, int));
112c33fcabaSmillert void	get_geometry __P((int, struct disklabel **, struct disklabel **));
113c33fcabaSmillert void	set_geometry __P((struct disklabel *, struct disklabel *, struct disklabel *, struct disklabel *, char *));
1149afbe9eeSmillert void	zero_partitions __P((struct disklabel *, u_int32_t *));
11596a888c6Smillert 
11696a888c6Smillert static u_int32_t starting_sector;
11796a888c6Smillert static u_int32_t ending_sector;
1182d8451b0Smillert static int expert;
1196fe57b42Smillert 
1206fe57b42Smillert /* from disklabel.c */
1216fe57b42Smillert int	checklabel __P((struct disklabel *));
1226fe57b42Smillert void	display __P((FILE *, struct disklabel *));
123bd6726faSmillert void	display_partition __P((FILE *, struct disklabel *, char **, int, char, int));
124af98caf3Sderaadt int	width_partition __P((struct disklabel *, int));
125af98caf3Sderaadt 
1266fe57b42Smillert struct disklabel *readlabel __P((int));
1276fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int));
1286fe57b42Smillert int	writelabel __P((int, char *, struct disklabel *));
1296fe57b42Smillert extern	char *bootarea, *specname;
13069220492Smillert extern	int donothing;
1314793b14cSmillert #ifdef DOSLABEL
13210bddbefSmillert extern	struct dos_partition *dosdp;	/* DOS partition, if found */
1334793b14cSmillert #endif
1346fe57b42Smillert 
1356fe57b42Smillert /*
1366fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
1376fe57b42Smillert  */
1386fe57b42Smillert int
1399785f718Smillert editor(lp, f, dev, fstabfile)
1406fe57b42Smillert 	struct disklabel *lp;
1416fe57b42Smillert 	int f;
142803ff7d5Smillert 	char *dev;
143bd6726faSmillert 	char *fstabfile;
1446fe57b42Smillert {
1456fe57b42Smillert 	struct disklabel lastlabel, tmplabel, label = *lp;
146c33fcabaSmillert 	struct disklabel *disk_geop, *bios_geop;
14796a888c6Smillert 	struct partition *pp;
14896a888c6Smillert 	u_int32_t freesectors;
1496fe57b42Smillert 	FILE *fp;
1506fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
151bd6726faSmillert 	char **mountpoints = NULL, **omountpoints, **tmpmountpoints;
152bd6726faSmillert 
153bd6726faSmillert 	/* Alloc and init mount point info */
154bd6726faSmillert 	if (fstabfile) {
155bd6726faSmillert 		if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
156bd6726faSmillert 		    !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
157bd6726faSmillert 		    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
158bd6726faSmillert 			errx(4, "out of memory");
159bd6726faSmillert 	}
1606fe57b42Smillert 
16196a888c6Smillert 	/* Don't allow disk type of "unknown" */
162803ff7d5Smillert 	getdisktype(&label, "You need to specify a type for this disk.", dev);
1636fe57b42Smillert 
164c33fcabaSmillert 	/* Get the on-disk and BIOS geometries if possible */
165c33fcabaSmillert 	get_geometry(f, &disk_geop, &bios_geop);
166c33fcabaSmillert 
167d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
1689785f718Smillert 	find_bounds(&label, bios_geop);
169d09f3941Smillert 
17096a888c6Smillert 	/* Set freesectors based on bounds and initial label */
171c0bdc608Smillert 	editor_countfree(&label, &freesectors);
17296a888c6Smillert 
17396a888c6Smillert 	/* Make sure there is no partition overlap. */
17496a888c6Smillert 	if (has_overlap(&label, &freesectors, 1))
1756fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1766fe57b42Smillert 
17796a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
178d09f3941Smillert 	pp = &label.d_partitions[RAW_PART];
17996a888c6Smillert 	if (label.d_npartitions < 3 || pp->p_size == 0) {
18096a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
18196a888c6Smillert 		if (label.d_npartitions < 3)
18296a888c6Smillert 			label.d_npartitions = 3;
18396a888c6Smillert 		pp->p_offset = 0;
18496a888c6Smillert 		pp->p_size = label.d_secperunit;
18596a888c6Smillert 		pp->p_fstype = FS_UNUSED;
18696a888c6Smillert 		pp->p_fsize = pp->p_frag = pp->p_cpg = 0;
18796a888c6Smillert 	}
1880f820bbbSmillert 
1896fe57b42Smillert #ifdef CYLCHECK
1906fe57b42Smillert 	puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically.");
1916fe57b42Smillert #endif
1926fe57b42Smillert 
193bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
19455403f76Smillert 	if (label.d_bbsize == 0)
19555403f76Smillert 		label.d_bbsize = BBSIZE;
19655403f76Smillert 	if (label.d_sbsize == 0)
19755403f76Smillert 		label.d_sbsize = SBSIZE;
198f98aebd4Smillert 
199440b1d70Smillert 	/* Interleave must be >= 1 */
200440b1d70Smillert 	if (label.d_interleave == 0)
201440b1d70Smillert 		label.d_interleave = 1;
202440b1d70Smillert 
20396a888c6Smillert 	puts("\nInitial label editor (enter '?' for help at any prompt)");
2046fe57b42Smillert 	lastlabel = label;
2056fe57b42Smillert 	for (;;) {
2066fe57b42Smillert 		fputs("> ", stdout);
2076fe57b42Smillert 		fflush(stdout);
2086fe57b42Smillert 		rewind(stdin);
2096e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
2106e0becc5Smillert 			putchar('\n');
2116e0becc5Smillert 			buf[0] = 'q';
2126e0becc5Smillert 			buf[1] = '\0';
2136e0becc5Smillert 		}
214260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
215260513deSmillert 			continue;
216260513deSmillert 		arg = strtok(NULL, " \t\r\n");
2176fe57b42Smillert 
2186fe57b42Smillert 		switch (*cmd) {
2196fe57b42Smillert 
2206fe57b42Smillert 		case '?':
221ea37abd3Sderaadt 		case 'h':
222617e6e4aSmillert 			editor_help(arg ? arg : "");
2236fe57b42Smillert 			break;
2246fe57b42Smillert 
2256fe57b42Smillert 		case 'a':
2266fe57b42Smillert 			tmplabel = lastlabel;
2276fe57b42Smillert 			lastlabel = label;
228bd6726faSmillert 			if (mountpoints != NULL) {
229bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
230bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
231bd6726faSmillert 			}
232bd6726faSmillert 			editor_add(&label, mountpoints, &freesectors, arg);
23396a888c6Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
23496a888c6Smillert 				lastlabel = tmplabel;
235bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
236bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
23796a888c6Smillert 			break;
23896a888c6Smillert 
23996a888c6Smillert 		case 'b':
24096a888c6Smillert 			tmplabel = lastlabel;
24196a888c6Smillert 			lastlabel = label;
242e8e8bdb7Sart 			set_bounds(&label, &freesectors);
2436fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2446fe57b42Smillert 				lastlabel = tmplabel;
2456fe57b42Smillert 			break;
2466fe57b42Smillert 
2476fe57b42Smillert 		case 'c':
2486fe57b42Smillert 			tmplabel = lastlabel;
2496fe57b42Smillert 			lastlabel = label;
25096a888c6Smillert 			editor_change(&label, &freesectors, arg);
2516fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2526fe57b42Smillert 				lastlabel = tmplabel;
2536fe57b42Smillert 			break;
2546fe57b42Smillert 
2559afbe9eeSmillert 		case 'D':
256*cdd7eb76Smillert 			tmplabel = lastlabel;
257*cdd7eb76Smillert 			lastlabel = label;
258*cdd7eb76Smillert 			if (ioctl(f, DIOCGPDINFO, &label) == 0)
2599afbe9eeSmillert 				editor_countfree(&label, &freesectors);
260*cdd7eb76Smillert 			else {
261*cdd7eb76Smillert 				warn("unable to get default partition table");
262*cdd7eb76Smillert 				lastlabel = tmplabel;
263*cdd7eb76Smillert 			}
2649afbe9eeSmillert 			break;
2659afbe9eeSmillert 
2666fe57b42Smillert 		case 'd':
2676fe57b42Smillert 			tmplabel = lastlabel;
2686fe57b42Smillert 			lastlabel = label;
269bd6726faSmillert 			if (mountpoints != NULL) {
270bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
271bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
272bd6726faSmillert 			}
273bd6726faSmillert 			editor_delete(&label, mountpoints, &freesectors, arg);
2746fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2756fe57b42Smillert 				lastlabel = tmplabel;
276bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
277bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
2786fe57b42Smillert 			break;
2796fe57b42Smillert 
2809afbe9eeSmillert 		case 'e':
2819afbe9eeSmillert 			tmplabel = lastlabel;
2829afbe9eeSmillert 			lastlabel = label;
2839afbe9eeSmillert 			edit_parms(&label, &freesectors);
2849afbe9eeSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2859afbe9eeSmillert 				lastlabel = tmplabel;
2869afbe9eeSmillert 			break;
2879afbe9eeSmillert 
288c33fcabaSmillert 		case 'g':
289c33fcabaSmillert 			tmplabel = lastlabel;
290c33fcabaSmillert 			lastlabel = label;
291c33fcabaSmillert 			set_geometry(&label, disk_geop, bios_geop, lp, arg);
292c33fcabaSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
293c33fcabaSmillert 				lastlabel = tmplabel;
294c33fcabaSmillert 			break;
295c33fcabaSmillert 
2966fe57b42Smillert 		case 'm':
2976fe57b42Smillert 			tmplabel = lastlabel;
2986fe57b42Smillert 			lastlabel = label;
299bd6726faSmillert 			if (mountpoints != NULL) {
300bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
301bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
302bd6726faSmillert 			}
303bd6726faSmillert 			editor_modify(&label, mountpoints, &freesectors, arg);
3046fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
3056fe57b42Smillert 				lastlabel = tmplabel;
306bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
307bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
308bd6726faSmillert 			break;
309bd6726faSmillert 
310bd6726faSmillert 		case 'n':
311bd6726faSmillert 			if (mountpoints == NULL) {
312bd6726faSmillert 				fputs("This option is not valid when run "
313bd6726faSmillert 				    "without the -F flag.\n", stderr);
314bd6726faSmillert 				break;
315bd6726faSmillert 			}
316bd6726faSmillert 			mpcopy(tmpmountpoints, omountpoints);
317bd6726faSmillert 			mpcopy(omountpoints, mountpoints);
318bd6726faSmillert 			editor_name(&label, mountpoints, arg);
319bd6726faSmillert 			if (mpequal(omountpoints, tmpmountpoints))
320bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
3216fe57b42Smillert 			break;
3226fe57b42Smillert 
3236fe57b42Smillert 		case 'p':
324bd6726faSmillert 			editor_display(&label, mountpoints, &freesectors,
325bd6726faSmillert 			    arg ? *arg : 0);
3266fe57b42Smillert 			break;
3276fe57b42Smillert 
328508086e9Smillert 		case 'M': {
329508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
330508086e9Smillert 			char *pager;
3315d12b01bSderaadt 			extern char manpage[];
3325d12b01bSderaadt 
333489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
334508086e9Smillert 				pager = _PATH_LESS;
335508086e9Smillert 			if ((fp = popen(pager, "w")) != NULL) {
3365d12b01bSderaadt 				(void) fwrite(manpage, strlen(manpage), 1, fp);
3375d12b01bSderaadt 				pclose(fp);
338508086e9Smillert 			} else
339508086e9Smillert 				warn("unable to execute %s", pager);
340508086e9Smillert 
341508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3425d12b01bSderaadt 			break;
343508086e9Smillert 		}
3445d12b01bSderaadt 
3456fe57b42Smillert 		case 'q':
34669220492Smillert 			if (donothing) {
34769220492Smillert 				puts("In no change mode, not writing label.");
34869220492Smillert 				return(1);
34969220492Smillert 			}
350bd6726faSmillert 			/* Save mountpoint info if there is any. */
351bd6726faSmillert 			if (mountpoints != NULL)
352bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
3536fe57b42Smillert 			if (memcmp(lp, &label, sizeof(label)) == 0) {
354bd6726faSmillert 				puts("No label changes.");
3556fe57b42Smillert 				return(1);
3566fe57b42Smillert 			}
3576fe57b42Smillert 			do {
358d0e67762Smillert 				arg = getstring("Write new label?",
359d0e67762Smillert 				    "Write the modified label to disk?",
360d0e67762Smillert 				    "y");
36196a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
36296a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
363d0e67762Smillert 				if (writelabel(f, bootarea, &label) == 0) {
3646fe57b42Smillert 					*lp = label;
3656fe57b42Smillert 					return(0);
3666fe57b42Smillert 				}
367d0e67762Smillert 				warnx("unable to write label");
368d0e67762Smillert 			}
3696fe57b42Smillert 			return(1);
3706fe57b42Smillert 			/* NOTREACHED */
3716fe57b42Smillert 			break;
3726fe57b42Smillert 
373c0bdc608Smillert 		case 'r':
374c0bdc608Smillert 		    /* Recalculate free space */
375c0bdc608Smillert 		    editor_countfree(&label, &freesectors);
376c0bdc608Smillert 		    puts("Recalculated free space.");
377c0bdc608Smillert 		    break;
378c0bdc608Smillert 
3796fe57b42Smillert 		case 's':
3806fe57b42Smillert 			if (arg == NULL) {
381c33fcabaSmillert 				arg = getstring("Filename",
3826fe57b42Smillert 				    "Name of the file to save label into.",
3836fe57b42Smillert 				    NULL);
38496a888c6Smillert 				if (arg == NULL && *arg == '\0')
3856fe57b42Smillert 					break;
3866fe57b42Smillert 			}
3876fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
3886fe57b42Smillert 				warn("cannot open %s", arg);
3896fe57b42Smillert 			} else {
3906fe57b42Smillert 				display(fp, &label);
3916fe57b42Smillert 				(void)fclose(fp);
3926fe57b42Smillert 			}
3936fe57b42Smillert 			break;
3946fe57b42Smillert 
3956fe57b42Smillert 		case 'u':
396bd6726faSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0 &&
397bd6726faSmillert 			    mountpoints != NULL &&
398bd6726faSmillert 			    mpequal(mountpoints, omountpoints)) {
3996fe57b42Smillert 				puts("Nothing to undo!");
4006fe57b42Smillert 			} else {
4016fe57b42Smillert 				tmplabel = label;
4026fe57b42Smillert 				label = lastlabel;
4036fe57b42Smillert 				lastlabel = tmplabel;
404c0bdc608Smillert 				/* Recalculate free space */
405c0bdc608Smillert 				editor_countfree(&label, &freesectors);
406bd6726faSmillert 				/* Restore mountpoints */
407bd6726faSmillert 				if (mountpoints != NULL)
408bd6726faSmillert 					mpcopy(mountpoints, omountpoints);
4096fe57b42Smillert 				puts("Last change undone.");
4106fe57b42Smillert 			}
4116fe57b42Smillert 			break;
4126fe57b42Smillert 
413040947cfSmillert 		case 'w':
414bd6726faSmillert 			if (donothing)  {
415040947cfSmillert 				puts("In no change mode, not writing label.");
416bd6726faSmillert 				break;
417bd6726faSmillert 			}
418bd6726faSmillert 			/* Save mountpoint info if there is any. */
419bd6726faSmillert 			if (mountpoints != NULL)
420bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
421bd6726faSmillert 			/* Save label if it has changed. */
422bd6726faSmillert 			if (memcmp(lp, &label, sizeof(label)) == 0)
423bd6726faSmillert 				puts("No label changes.");
424040947cfSmillert 			else if (writelabel(f, bootarea, &label) != 0)
425040947cfSmillert 				warnx("unable to write label");
4265af08e9cSmillert 			else
4275af08e9cSmillert 				*lp = label;
428040947cfSmillert 			break;
429040947cfSmillert 
4302d8451b0Smillert 		case 'X':
4312d8451b0Smillert 			expert = !expert;
4322d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
4332d8451b0Smillert 			    "Exiting");
4342d8451b0Smillert 			break;
4352d8451b0Smillert 
4366fe57b42Smillert 		case 'x':
4376fe57b42Smillert 			return(1);
4386fe57b42Smillert 			break;
4396fe57b42Smillert 
4409afbe9eeSmillert 		case 'z':
441*cdd7eb76Smillert 			tmplabel = lastlabel;
442*cdd7eb76Smillert 			lastlabel = label;
4439afbe9eeSmillert 			zero_partitions(&label, &freesectors);
4446fe57b42Smillert 			break;
4456fe57b42Smillert 
4469afbe9eeSmillert 		case '\n':
4476fe57b42Smillert 			break;
4486fe57b42Smillert 
4496fe57b42Smillert 		default:
4506fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4516fe57b42Smillert 			break;
4526fe57b42Smillert 		}
4536fe57b42Smillert 	}
4546fe57b42Smillert }
4556fe57b42Smillert 
4566fe57b42Smillert /*
4576fe57b42Smillert  * Add a new partition.
4586fe57b42Smillert  */
4596fe57b42Smillert void
460bd6726faSmillert editor_add(lp, mp, freep, p)
4616fe57b42Smillert 	struct disklabel *lp;
462bd6726faSmillert 	char **mp;
4636fe57b42Smillert 	u_int32_t *freep;
4646fe57b42Smillert 	char *p;
4656fe57b42Smillert {
46696a888c6Smillert 	struct partition *pp;
46796a888c6Smillert 	struct diskchunk *chunks;
4686fe57b42Smillert 	char buf[BUFSIZ];
4696fe57b42Smillert 	int i, partno;
47096a888c6Smillert 	u_int32_t ui, old_offset, old_size;
4716fe57b42Smillert 
4726fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
4736fe57b42Smillert 	if (*freep == 0) {
4746fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
4756fe57b42Smillert 		    stderr);
4766fe57b42Smillert 		return;
4776fe57b42Smillert 	}
4786fe57b42Smillert 
4796fe57b42Smillert 	/* XXX - make more like other editor_* */
4806fe57b42Smillert 	if (p != NULL) {
4816fe57b42Smillert 		partno = p[0] - 'a';
4829afbe9eeSmillert 		if (partno < 0 || partno == RAW_PART ||
4839afbe9eeSmillert 		    partno >= MAXPARTITIONS) {
4846fe57b42Smillert 			fprintf(stderr,
485e6ab932bSmillert 			    "Partition must be between 'a' and '%c' "
486e6ab932bSmillert 			    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
4876fe57b42Smillert 			return;
48896a888c6Smillert 		} else if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
489f6299b35Sderaadt 		    lp->d_partitions[partno].p_size != 0) {
490f6299b35Sderaadt 			fprintf(stderr,
491f6299b35Sderaadt 			    "Partition '%c' exists.  Delete it first.\n",
492f6299b35Sderaadt 			    p[0]);
493f6299b35Sderaadt 			return;
4946fe57b42Smillert 		}
4956fe57b42Smillert 	} else {
4969c5f1350Smillert 		/* Find first unused partition that is not 'c' */
4976fe57b42Smillert 		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {
4989afbe9eeSmillert 			if (lp->d_partitions[partno].p_size == 0 &&
4999afbe9eeSmillert 			    partno != RAW_PART)
5006fe57b42Smillert 				break;
5016fe57b42Smillert 		}
5026fe57b42Smillert 		if (partno < MAXPARTITIONS) {
5036fe57b42Smillert 			buf[0] = partno + 'a';
5046fe57b42Smillert 			buf[1] = '\0';
5056fe57b42Smillert 			p = &buf[0];
5066fe57b42Smillert 		} else
5076fe57b42Smillert 			p = NULL;
5086fe57b42Smillert 		for (;;) {
509c33fcabaSmillert 			p = getstring("partition",
5106fe57b42Smillert 			    "The letter of the new partition, a - p.", p);
51196a888c6Smillert 			if (p == NULL)
51296a888c6Smillert 				return;
5136fe57b42Smillert 			partno = p[0] - 'a';
51496a888c6Smillert 			if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
51596a888c6Smillert 			    lp->d_partitions[partno].p_size != 0) {
51696a888c6Smillert 				fprintf(stderr,
51796a888c6Smillert 				    "Partition '%c' already exists.\n", p[0]);
51896a888c6Smillert 			} else if (partno >= 0 && partno < MAXPARTITIONS)
5196fe57b42Smillert 				break;
5206fe57b42Smillert 			fprintf(stderr,
5216fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
5226fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
5236fe57b42Smillert 		}
5246fe57b42Smillert 	}
52596a888c6Smillert 
52696a888c6Smillert 	/* Increase d_npartitions if necesary */
52796a888c6Smillert 	if (partno >= lp->d_npartitions)
52896a888c6Smillert 		lp->d_npartitions = partno + 1;
52996a888c6Smillert 
53096a888c6Smillert 	/* Set defaults */
5316fe57b42Smillert 	pp = &lp->d_partitions[partno];
5326fe57b42Smillert 	if (partno >= lp->d_npartitions)
5336fe57b42Smillert 		lp->d_npartitions = partno + 1;
5346fe57b42Smillert 	memset(pp, 0, sizeof(*pp));
5352d8451b0Smillert 	pp->p_size = *freep;
5362d8451b0Smillert 	pp->p_offset = next_offset(lp, &pp->p_size);
53796a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
5386fe57b42Smillert 	pp->p_fsize = 1024;
5396fe57b42Smillert 	pp->p_frag = 8;
5406fe57b42Smillert 	pp->p_cpg = 16;
54196a888c6Smillert 	old_offset = pp->p_offset;
54296a888c6Smillert 	old_size = pp->p_size;
54396a888c6Smillert 
54496a888c6Smillert getoff1:
54596a888c6Smillert 	/* Get offset */
54624a2c1a4Smillert 	if (get_offset(lp, partno) != 0) {
54796a888c6Smillert 		pp->p_size = 0;			/* effective delete */
54896a888c6Smillert 		return;
54996a888c6Smillert 	}
55096a888c6Smillert 
55196a888c6Smillert 	/* Recompute recommended size based on new offset */
55296a888c6Smillert 	ui = pp->p_fstype;
55396a888c6Smillert 	pp->p_fstype = FS_UNUSED;
55496a888c6Smillert 	chunks = free_chunks(lp);
55596a888c6Smillert 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
55696a888c6Smillert 		if (pp->p_offset >= chunks[i].start &&
55796a888c6Smillert 		    pp->p_offset < chunks[i].stop) {
55896a888c6Smillert 			pp->p_size = chunks[i].stop - pp->p_offset;
55996a888c6Smillert 			break;
56096a888c6Smillert 		}
56196a888c6Smillert 	}
56296a888c6Smillert 	pp->p_fstype = ui;
56396a888c6Smillert 
56496a888c6Smillert 	/* Get size */
56524a2c1a4Smillert 	if (get_size(lp, partno, freep, 1) != 0 || pp->p_size == 0) {
56696a888c6Smillert 		pp->p_size = 0;			/* effective delete */
56796a888c6Smillert 		return;
56896a888c6Smillert 	}
56996a888c6Smillert 
57096a888c6Smillert 	/* Check for overlap */
57196a888c6Smillert 	if (has_overlap(lp, freep, 0)) {
5724793b14cSmillert 		printf("\nPlease re-enter an offset and size for partition "
5734793b14cSmillert 		    "%c.\n", 'a' + partno);
57496a888c6Smillert 		pp->p_offset = old_offset;
57596a888c6Smillert 		pp->p_size = old_size;
57696a888c6Smillert 		goto getoff1;		/* Yeah, I know... */
57796a888c6Smillert 	}
5786fe57b42Smillert 
5797a201fc6Smillert 	/* Get filesystem type and mountpoint */
5807a201fc6Smillert 	if (get_fstype(lp, partno) != 0 || get_mp(lp, mp, partno) != 0) {
58196a888c6Smillert 		pp->p_size = 0;			/* effective delete */
58296a888c6Smillert 		return;
5836fe57b42Smillert 	}
5846fe57b42Smillert 
5852d8451b0Smillert 	if (expert && pp->p_fstype == FS_BSDFFS) {
5867a201fc6Smillert 		/* Get fsize, bsize, and cpg */
5877a201fc6Smillert 		if (get_fsize(lp, partno) != 0 || get_bsize(lp, partno) != 0 ||
5887a201fc6Smillert 		    get_cpg(lp, partno) != 0) {
58996a888c6Smillert 			pp->p_size = 0;			/* effective delete */
59096a888c6Smillert 			return;
5916fe57b42Smillert 		}
5926fe57b42Smillert 	}
59324a2c1a4Smillert 
59496a888c6Smillert 	/* Update free sector count and make sure things stay contiguous. */
5956fe57b42Smillert 	*freep -= pp->p_size;
59696a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
59796a888c6Smillert 	    has_overlap(lp, freep, -1))
5986fe57b42Smillert 		make_contiguous(lp);
5996fe57b42Smillert }
6006fe57b42Smillert 
6016fe57b42Smillert /*
602bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
603bd6726faSmillert  */
604bd6726faSmillert void
605bd6726faSmillert editor_name(lp, mp, p)
606bd6726faSmillert 	struct disklabel *lp;
607bd6726faSmillert 	char **mp;
608bd6726faSmillert 	char *p;
609bd6726faSmillert {
610bd6726faSmillert 	struct partition *pp;
611bd6726faSmillert 	int partno;
612bd6726faSmillert 
613bd6726faSmillert 	/* Change which partition? */
614bd6726faSmillert 	if (p == NULL) {
615c33fcabaSmillert 		p = getstring("partition to name",
616bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
617bd6726faSmillert 	}
618bd6726faSmillert 	if (p == NULL) {
619bd6726faSmillert 		fputs("Command aborted\n", stderr);
620bd6726faSmillert 		return;
621bd6726faSmillert 	}
622bd6726faSmillert 	partno = p[0] - 'a';
623bd6726faSmillert 	pp = &lp->d_partitions[partno];
624bd6726faSmillert 	if (partno < 0 || partno >= lp->d_npartitions) {
625bd6726faSmillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
626bd6726faSmillert 		    'a' + lp->d_npartitions - 1);
627bd6726faSmillert 		return;
628bd6726faSmillert 	} else if (partno >= lp->d_npartitions ||
629bd6726faSmillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
630bd6726faSmillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
631bd6726faSmillert 		return;
632bd6726faSmillert 	}
633bd6726faSmillert 
634bd6726faSmillert 	/* Not all fstypes can be named */
635bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
636bd6726faSmillert 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER) {
637bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
638baa55472Smillert 		    fstypenames[lp->d_partitions[partno].p_fstype]);
639bd6726faSmillert 		return;
640bd6726faSmillert 	}
641bd6726faSmillert 
642ddaff619Smillert 	get_mp(lp, mp, partno);
643bd6726faSmillert }
644bd6726faSmillert 
645bd6726faSmillert /*
6466fe57b42Smillert  * Change an existing partition.
6476fe57b42Smillert  */
6486fe57b42Smillert void
649bd6726faSmillert editor_modify(lp, mp, freep, p)
6506fe57b42Smillert 	struct disklabel *lp;
651bd6726faSmillert 	char **mp;
6526fe57b42Smillert 	u_int32_t *freep;
6536fe57b42Smillert 	char *p;
6546fe57b42Smillert {
6556fe57b42Smillert 	struct partition origpart, *pp;
6566fe57b42Smillert 	int partno;
6576fe57b42Smillert 
6586fe57b42Smillert 	/* Change which partition? */
6596fe57b42Smillert 	if (p == NULL) {
660c33fcabaSmillert 		p = getstring("partition to modify",
6616fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
6626fe57b42Smillert 	}
66396a888c6Smillert 	if (p == NULL) {
66496a888c6Smillert 		fputs("Command aborted\n", stderr);
66596a888c6Smillert 		return;
66696a888c6Smillert 	}
6676fe57b42Smillert 	partno = p[0] - 'a';
6686fe57b42Smillert 	pp = &lp->d_partitions[partno];
6696fe57b42Smillert 	origpart = lp->d_partitions[partno];
6706fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
6716fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
6726fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
6736fe57b42Smillert 		return;
6746fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
6756fe57b42Smillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
6766fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
6776fe57b42Smillert 		return;
6786fe57b42Smillert 	}
6796fe57b42Smillert 
6806fe57b42Smillert 	/* Get filesystem type */
68124a2c1a4Smillert 	if (get_fstype(lp, partno) != 0) {
68224a2c1a4Smillert 		*pp = origpart;			/* undo changes */
68396a888c6Smillert 		return;
68496a888c6Smillert 	}
6856fe57b42Smillert 
6866fe57b42Smillert 	/* Did they disable/enable the partition? */
687229f463eSmillert 	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&
688229f463eSmillert 	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)
6896fe57b42Smillert 		*freep += origpart.p_size;
690229f463eSmillert 	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
691229f463eSmillert 	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {
6926fe57b42Smillert 		if (pp->p_size > *freep) {
6936fe57b42Smillert 			fprintf(stderr,
69496a888c6Smillert 			    "Warning, need %u sectors but there are only %u "
6956fe57b42Smillert 			    "free.  Setting size to %u.\n", pp->p_size, *freep,
6966fe57b42Smillert 			    *freep);
6976fe57b42Smillert 			pp->p_fstype = *freep;
6986fe57b42Smillert 			*freep = 0;
6996fe57b42Smillert 		} else
7006fe57b42Smillert 			*freep -= pp->p_size;		/* have enough space */
7016fe57b42Smillert 	}
7026fe57b42Smillert 
7036fe57b42Smillert getoff2:
7046fe57b42Smillert 	/* Get offset */
70524a2c1a4Smillert 	if (get_offset(lp, partno) != 0) {
70696a888c6Smillert 		*pp = origpart;			/* undo changes */
70796a888c6Smillert 		return;
7086fe57b42Smillert 	}
7096fe57b42Smillert 
7106fe57b42Smillert 	/* Get size */
71124a2c1a4Smillert 	if (get_size(lp, partno, freep, 0) != 0 || pp->p_size == 0) {
71224a2c1a4Smillert 		pp->p_size = 0;			/* effective delete */
71396a888c6Smillert 		return;
7146fe57b42Smillert 	}
7156fe57b42Smillert 
7166fe57b42Smillert 	/* Check for overlap and restore if not resolved */
7176fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
7186fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
7196fe57b42Smillert 		pp->p_offset = origpart.p_offset;
7206fe57b42Smillert 		pp->p_size = origpart.p_size;
7216fe57b42Smillert 		goto getoff2;		/* Yeah, I know... */
7226fe57b42Smillert 	}
7236fe57b42Smillert 
7247a201fc6Smillert 	/* get mount point */
7257a201fc6Smillert 	if (get_mp(lp, mp, partno) != 0) {
7267a201fc6Smillert 		*pp = origpart;			/* undo changes */
7277a201fc6Smillert 		return;
7287a201fc6Smillert 	}
7297a201fc6Smillert 
7302d8451b0Smillert 	if (expert && (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED)){
7316fe57b42Smillert 		/* get fsize */
73224a2c1a4Smillert 		if (get_fsize(lp, partno) != 0) {
73396a888c6Smillert 			*pp = origpart;		/* undo changes */
73496a888c6Smillert 			return;
7356fe57b42Smillert 		}
7366fe57b42Smillert 
7376fe57b42Smillert 		/* get bsize */
73824a2c1a4Smillert 		if (get_bsize(lp, partno) != 0) {
73996a888c6Smillert 			*pp = origpart;		/* undo changes */
74096a888c6Smillert 			return;
7416fe57b42Smillert 		}
7426fe57b42Smillert 
7436fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
7446fe57b42Smillert 			/* get cpg */
74524a2c1a4Smillert 			if (get_cpg(lp, partno) != 0) {
74696a888c6Smillert 				*pp = origpart;	/* undo changes */
74796a888c6Smillert 				return;
7486fe57b42Smillert 			}
7496fe57b42Smillert 		}
7506fe57b42Smillert 	}
7516fe57b42Smillert 
7526fe57b42Smillert 	/* Make sure things stay contiguous. */
75396a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
75496a888c6Smillert 	    has_overlap(lp, freep, -1))
7556fe57b42Smillert 		make_contiguous(lp);
7566fe57b42Smillert }
7576fe57b42Smillert 
7586fe57b42Smillert /*
7596fe57b42Smillert  * Delete an existing partition.
7606fe57b42Smillert  */
7616fe57b42Smillert void
762bd6726faSmillert editor_delete(lp, mp, freep, p)
7636fe57b42Smillert 	struct disklabel *lp;
764bd6726faSmillert 	char **mp;
7656fe57b42Smillert 	u_int32_t *freep;
7666fe57b42Smillert 	char *p;
7676fe57b42Smillert {
7686fe57b42Smillert 	int c;
7696fe57b42Smillert 
7706fe57b42Smillert 	if (p == NULL) {
771c33fcabaSmillert 		p = getstring("partition to delete",
772945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
773945ae268Smillert 		    NULL);
7746fe57b42Smillert 	}
77596a888c6Smillert 	if (p == NULL) {
77696a888c6Smillert 		fputs("Command aborted\n", stderr);
77796a888c6Smillert 		return;
77896a888c6Smillert 	}
779945ae268Smillert 	if (p[0] == '*') {
780945ae268Smillert 		for (c = 0; c < lp->d_npartitions; c++) {
7819afbe9eeSmillert 			if (c == RAW_PART)
782945ae268Smillert 				continue;
783945ae268Smillert 
784945ae268Smillert 			/* Update free sector count. */
785945ae268Smillert 			if (lp->d_partitions[c].p_fstype != FS_UNUSED &&
786945ae268Smillert 			    lp->d_partitions[c].p_fstype != FS_BOOT &&
787945ae268Smillert 			    lp->d_partitions[c].p_size != 0)
788945ae268Smillert 				*freep += lp->d_partitions[c].p_size;
789945ae268Smillert 
790945ae268Smillert 			(void)memset(&lp->d_partitions[c], 0,
791945ae268Smillert 			    sizeof(lp->d_partitions[c]));
792945ae268Smillert 		}
793945ae268Smillert 		return;
794945ae268Smillert 	}
7956fe57b42Smillert 	c = p[0] - 'a';
7966fe57b42Smillert 	if (c < 0 || c >= lp->d_npartitions)
7976fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
7986fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
7996fe57b42Smillert 	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==
8006fe57b42Smillert 	    FS_UNUSED && lp->d_partitions[c].p_size == 0))
8016fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);
8029afbe9eeSmillert 	else if (c == RAW_PART)
803617e6e4aSmillert 		fputs(
804617e6e4aSmillert "You may not delete the 'c' partition.  The 'c' partition must exist and\n"
805617e6e4aSmillert "should span the entire disk.  By default it is of type 'unused' and so\n"
806617e6e4aSmillert "does not take up any space.\n", stderr);
8076fe57b42Smillert 	else {
80896a888c6Smillert 		/* Update free sector count. */
809e49c5d78Smillert 		if (lp->d_partitions[c].p_offset < ending_sector &&
810e49c5d78Smillert 		    lp->d_partitions[c].p_offset >= starting_sector &&
811e49c5d78Smillert 		    lp->d_partitions[c].p_fstype != FS_UNUSED &&
812229f463eSmillert 		    lp->d_partitions[c].p_fstype != FS_BOOT &&
8136fe57b42Smillert 		    lp->d_partitions[c].p_size != 0)
8146fe57b42Smillert 			*freep += lp->d_partitions[c].p_size;
8156fe57b42Smillert 
8166fe57b42Smillert 		/* Really delete it (as opposed to just setting to "unused") */
8176fe57b42Smillert 		(void)memset(&lp->d_partitions[c], 0,
8186fe57b42Smillert 		    sizeof(lp->d_partitions[c]));
8196fe57b42Smillert 	}
820bd6726faSmillert 	if (mp != NULL && mp[c] != NULL) {
821bd6726faSmillert 		free(mp[c]);
822bd6726faSmillert 		mp[c] = NULL;
823bd6726faSmillert 	}
8246fe57b42Smillert }
8256fe57b42Smillert 
8266fe57b42Smillert /*
8276fe57b42Smillert  * Simplified display() for use with the builtin editor.
8286fe57b42Smillert  */
8296fe57b42Smillert void
830bd6726faSmillert editor_display(lp, mp, freep, unit)
8316fe57b42Smillert 	struct disklabel *lp;
832bd6726faSmillert 	char **mp;
8336fe57b42Smillert 	u_int32_t *freep;
8346fe57b42Smillert 	char unit;
8356fe57b42Smillert {
8366fe57b42Smillert 	int i;
837af98caf3Sderaadt 	int width;
8386fe57b42Smillert 
8396fe57b42Smillert 	printf("device: %s\n", specname);
8400f820bbbSmillert 	printf("type: %s\n", dktypenames[lp->d_type]);
8416fe57b42Smillert 	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
8426fe57b42Smillert 	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
8436fe57b42Smillert 	printf("bytes/sector: %ld\n", (long)lp->d_secsize);
8446fe57b42Smillert 	printf("sectors/track: %ld\n", (long)lp->d_nsectors);
8456fe57b42Smillert 	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);
8466fe57b42Smillert 	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);
8476fe57b42Smillert 	printf("cylinders: %ld\n", (long)lp->d_ncylinders);
8486fe57b42Smillert 	printf("total sectors: %ld\n", (long)lp->d_secperunit);
8496fe57b42Smillert 	printf("free sectors: %u\n", *freep);
8506fe57b42Smillert 	printf("rpm: %ld\n", (long)lp->d_rpm);
8516fe57b42Smillert 	printf("\n%d partitions:\n", lp->d_npartitions);
852af98caf3Sderaadt 	width = width_partition(lp, unit);
853af98caf3Sderaadt 	printf("#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n",
854af98caf3Sderaadt 		width, width, "size", width, width, "offset");
8556fe57b42Smillert 	for (i = 0; i < lp->d_npartitions; i++)
856bd6726faSmillert 		display_partition(stdout, lp, mp, i, unit, width);
8576fe57b42Smillert }
8586fe57b42Smillert 
8596fe57b42Smillert /*
8606fe57b42Smillert  * Find the next reasonable starting offset and returns it.
86196a888c6Smillert  * Assumes there is a least one free sector left (returns 0 if not).
8626fe57b42Smillert  */
8636fe57b42Smillert u_int32_t
8642d8451b0Smillert next_offset(lp, sizep)
8656fe57b42Smillert 	struct disklabel *lp;
8662d8451b0Smillert 	u_int32_t *sizep;
8676fe57b42Smillert {
868f0b4d0a9Smillert 	struct partition **spp;
86996a888c6Smillert 	struct diskchunk *chunks;
870f0b4d0a9Smillert 	u_int16_t npartitions;
87196a888c6Smillert 	u_int32_t new_offset, new_size;
87296a888c6Smillert 	int i, good_offset;
8736fe57b42Smillert 
874a7e61405Smillert 	/* Get a sorted list of the partitions */
87596a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
8762d8451b0Smillert 		return(starting_sector);
877f0b4d0a9Smillert 
87896a888c6Smillert 	new_offset = starting_sector;
879f0b4d0a9Smillert 	for (i = 0; i < npartitions; i++ ) {
8806fe57b42Smillert 		/*
8816fe57b42Smillert 		 * Is new_offset inside this partition?  If so,
88296a888c6Smillert 		 * make it the next sector after the partition ends.
8836fe57b42Smillert 		 */
8844793b14cSmillert 		if (spp[i]->p_offset + spp[i]->p_size < ending_sector &&
8854793b14cSmillert 		    ((new_offset >= spp[i]->p_offset &&
88696a888c6Smillert 		    new_offset < spp[i]->p_offset + spp[i]->p_size) ||
8872d8451b0Smillert 		    (new_offset + *sizep >= spp[i]->p_offset && new_offset
8882d8451b0Smillert 		    + *sizep <= spp[i]->p_offset + spp[i]->p_size)))
889f0b4d0a9Smillert 			new_offset = spp[i]->p_offset + spp[i]->p_size;
8906fe57b42Smillert 	}
8916fe57b42Smillert 
89296a888c6Smillert 	/* Did we find a suitable offset? */
89396a888c6Smillert 	for (good_offset = 1, i = 0; i < npartitions; i++ ) {
8942d8451b0Smillert 		if (new_offset + *sizep >= spp[i]->p_offset &&
8952d8451b0Smillert 		    new_offset + *sizep <= spp[i]->p_offset + spp[i]->p_size) {
89696a888c6Smillert 			/* Nope */
89796a888c6Smillert 			good_offset = 0;
89896a888c6Smillert 			break;
89996a888c6Smillert 		}
90096a888c6Smillert 	}
90196a888c6Smillert 
90296a888c6Smillert 	/* Specified size is too big, find something that fits */
90396a888c6Smillert 	if (!good_offset) {
90496a888c6Smillert 		chunks = free_chunks(lp);
90596a888c6Smillert 		new_size = 0;
90696a888c6Smillert 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
90796a888c6Smillert 			if (chunks[i].stop - chunks[i].start > new_size) {
90896a888c6Smillert 			    new_size = chunks[i].stop - chunks[i].start;
90996a888c6Smillert 			    new_offset = chunks[i].start;
91096a888c6Smillert 			}
91196a888c6Smillert 		}
9124793b14cSmillert 		/* XXX - should do something intelligent if new_size == 0 */
9132d8451b0Smillert 		*sizep = new_size;
91496a888c6Smillert 	}
91596a888c6Smillert 
916f0b4d0a9Smillert 	(void)free(spp);
9176fe57b42Smillert 	return(new_offset);
9186fe57b42Smillert }
9196fe57b42Smillert 
9206fe57b42Smillert /*
9216fe57b42Smillert  * Change the size of an existing partition.
9226fe57b42Smillert  */
9236fe57b42Smillert void
9246fe57b42Smillert editor_change(lp, freep, p)
9256fe57b42Smillert 	struct disklabel *lp;
9266fe57b42Smillert 	u_int32_t *freep;
9276fe57b42Smillert 	char *p;
9286fe57b42Smillert {
9296fe57b42Smillert 	int partno;
9306fe57b42Smillert 	u_int32_t newsize;
9314b9a3bdaSmillert 	struct partition *pp;
9326fe57b42Smillert 
9336fe57b42Smillert 	if (p == NULL) {
934c33fcabaSmillert 		p = getstring("partition to change size",
9356fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
9366fe57b42Smillert 	}
93796a888c6Smillert 	if (p == NULL) {
93896a888c6Smillert 		fputs("Command aborted\n", stderr);
93996a888c6Smillert 		return;
94096a888c6Smillert 	}
9416fe57b42Smillert 	partno = p[0] - 'a';
9426fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
9436fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
9446fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
9456fe57b42Smillert 		return;
9466fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
947229f463eSmillert 	    lp->d_partitions[partno].p_size == 0) {
9486fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
9496fe57b42Smillert 		return;
9506fe57b42Smillert 	}
9514b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
9526fe57b42Smillert 
9536fe57b42Smillert 	printf("Partition %c is currently %u sectors in size (%u free).\n",
9544b9a3bdaSmillert 	    partno + 'a', pp->p_size, *freep);
955229f463eSmillert 	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */
9566fe57b42Smillert 	newsize = getuint(lp, partno, "new size", "Size of the partition.  "
9576fe57b42Smillert 	    "You may also say +/- amount for a relative change.",
9584b9a3bdaSmillert 	    pp->p_size, pp->p_size + *freep, pp->p_offset, DO_CONVERSIONS |
9594b9a3bdaSmillert 	    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
96096a888c6Smillert 	if (newsize == UINT_MAX - 1) {
96196a888c6Smillert 		fputs("Command aborted\n", stderr);
96296a888c6Smillert 		return;
96396a888c6Smillert 	} else if (newsize == UINT_MAX) {
9646fe57b42Smillert 		fputs("Invalid entry\n", stderr);
9656fe57b42Smillert 		return;
9664b9a3bdaSmillert 	} else if (newsize == pp->p_size)
9676fe57b42Smillert 		return;
9686fe57b42Smillert 
9694b9a3bdaSmillert 	if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT) {
9704b9a3bdaSmillert 		if (newsize > pp->p_size) {
9714b9a3bdaSmillert 			if (newsize - pp->p_size > *freep) {
9726fe57b42Smillert 				fprintf(stderr,
9736fe57b42Smillert 				    "Only %u sectors free, you asked for %u\n",
9744b9a3bdaSmillert 				    *freep, newsize - pp->p_size);
9756fe57b42Smillert 				return;
9766fe57b42Smillert 			}
9774b9a3bdaSmillert 			*freep -= newsize - pp->p_size;
9784b9a3bdaSmillert 		} else if (newsize < pp->p_size) {
9794b9a3bdaSmillert 			*freep += pp->p_size - newsize;
9806fe57b42Smillert 		}
9816fe57b42Smillert 	} else {
9829afbe9eeSmillert 		if (partno == RAW_PART && newsize +
9834b9a3bdaSmillert 		    pp->p_offset > lp->d_secperunit) {
9846fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
9856fe57b42Smillert 			    stderr);
9866fe57b42Smillert 			return;
9876fe57b42Smillert 		}
9886fe57b42Smillert 	}
9894b9a3bdaSmillert 	pp->p_size = newsize;
9904b9a3bdaSmillert 	if (newsize + pp->p_offset > ending_sector ||
99196a888c6Smillert 	    has_overlap(lp, freep, -1))
9926fe57b42Smillert 		make_contiguous(lp);
9936fe57b42Smillert }
9946fe57b42Smillert 
9956fe57b42Smillert void
9966fe57b42Smillert make_contiguous(lp)
9976fe57b42Smillert 	struct disklabel *lp;
9986fe57b42Smillert {
9996fe57b42Smillert 	struct partition **spp;
10006fe57b42Smillert 	u_int16_t npartitions;
10016fe57b42Smillert 	int i;
10026fe57b42Smillert 
1003a7e61405Smillert 	/* Get a sorted list of the partitions */
100496a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
100596a888c6Smillert 		return;
10066fe57b42Smillert 
10076fe57b42Smillert 	/*
1008a7e61405Smillert 	 * Make everything contiguous but don't muck with start of the first one
100996a888c6Smillert 	 * or partitions not in the BSD part of the label.
10106fe57b42Smillert 	 */
101196a888c6Smillert 	for (i = 1; i < npartitions; i++) {
101296a888c6Smillert 		if (spp[i]->p_offset >= starting_sector ||
101396a888c6Smillert 		    spp[i]->p_offset < ending_sector)
101496a888c6Smillert 			spp[i]->p_offset =
101596a888c6Smillert 			    spp[i - 1]->p_offset + spp[i - 1]->p_size;
101696a888c6Smillert 	}
1017f0b4d0a9Smillert 
1018f0b4d0a9Smillert 	(void)free(spp);
10196fe57b42Smillert }
10206fe57b42Smillert 
10216fe57b42Smillert /*
10226fe57b42Smillert  * Sort the partitions based on starting offset.
10236fe57b42Smillert  * This assumes there can be no overlap.
10246fe57b42Smillert  */
10256fe57b42Smillert int
10266fe57b42Smillert partition_cmp(e1, e2)
10276fe57b42Smillert 	const void *e1, *e2;
10286fe57b42Smillert {
10296fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10306fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10316fe57b42Smillert 
10326fe57b42Smillert 	return((int)(p1->p_offset - p2->p_offset));
10336fe57b42Smillert }
10346fe57b42Smillert 
10356fe57b42Smillert char *
1036c33fcabaSmillert getstring(prompt, helpstring, oval)
10376fe57b42Smillert 	char *prompt;
10386fe57b42Smillert 	char *helpstring;
10396fe57b42Smillert 	char *oval;
10406fe57b42Smillert {
10416fe57b42Smillert 	static char buf[BUFSIZ];
10426fe57b42Smillert 	int n;
10436fe57b42Smillert 
10446fe57b42Smillert 	buf[0] = '\0';
10456fe57b42Smillert 	do {
10466fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
10476fe57b42Smillert 		fflush(stdout);
10486fe57b42Smillert 		rewind(stdin);
10496e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1050260513deSmillert 			buf[0] = '\0';
105196a888c6Smillert 			if (feof(stdin)) {
105296a888c6Smillert 				putchar('\n');
105396a888c6Smillert 				return(NULL);
105496a888c6Smillert 			}
10556e0becc5Smillert 		}
10566fe57b42Smillert 		n = strlen(buf);
10576fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
10586fe57b42Smillert 			buf[--n] = '\0';
10596fe57b42Smillert 		if (buf[0] == '?')
10606fe57b42Smillert 			puts(helpstring);
10616fe57b42Smillert 		else if (oval != NULL && buf[0] == '\0') {
10626fe57b42Smillert 			(void)strncpy(buf, oval, sizeof(buf) - 1);
10636fe57b42Smillert 			buf[sizeof(buf) - 1] = '\0';
10646fe57b42Smillert 		}
10656fe57b42Smillert 	} while (buf[0] == '?');
10666fe57b42Smillert 
10676fe57b42Smillert 	return(&buf[0]);
10686fe57b42Smillert }
10696fe57b42Smillert 
10706fe57b42Smillert /*
10716fe57b42Smillert  * Returns UINT_MAX on error
107224a2c1a4Smillert  * Usually only called by helper functions.
10736fe57b42Smillert  */
10746fe57b42Smillert u_int32_t
10754b9a3bdaSmillert getuint(lp, partno, prompt, helpstring, oval, maxval, offset, flags)
10766fe57b42Smillert 	struct disklabel *lp;
10776fe57b42Smillert 	int partno;
10786fe57b42Smillert 	char *prompt;
10796fe57b42Smillert 	char *helpstring;
10806fe57b42Smillert 	u_int32_t oval;
10816fe57b42Smillert 	u_int32_t maxval;		/* XXX - used inconsistently */
10824b9a3bdaSmillert 	u_int32_t offset;
10836fe57b42Smillert 	int flags;
10846fe57b42Smillert {
10856fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
10866fe57b42Smillert 	u_int32_t rval = oval;
10876fe57b42Smillert 	size_t n;
10886fe57b42Smillert 	int mult = 1;
108996a888c6Smillert 	double d;
10906fe57b42Smillert 
10914b9a3bdaSmillert 	/* We only care about the remainder */
10924b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
10934b9a3bdaSmillert 
10946fe57b42Smillert 	buf[0] = '\0';
10956fe57b42Smillert 	do {
10966fe57b42Smillert 		printf("%s: [%u] ", prompt, oval);
10976fe57b42Smillert 		fflush(stdout);
10986fe57b42Smillert 		rewind(stdin);
10996e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11006e0becc5Smillert 			buf[0] = '\0';
110196a888c6Smillert 			if (feof(stdin)) {
110296a888c6Smillert 				putchar('\n');
110396a888c6Smillert 				return(UINT_MAX - 1);
110496a888c6Smillert 			}
11056e0becc5Smillert 		}
11066fe57b42Smillert 		n = strlen(buf);
11076fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11086fe57b42Smillert 			buf[--n] = '\0';
11096fe57b42Smillert 		if (buf[0] == '?')
11106fe57b42Smillert 			puts(helpstring);
11116fe57b42Smillert 	} while (buf[0] == '?');
11126fe57b42Smillert 
11136fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11146fe57b42Smillert 		rval = maxval;
11156fe57b42Smillert 	} else {
11166fe57b42Smillert 		/* deal with units */
11176fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11186fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
111996a888c6Smillert 				switch (tolower(buf[n-1])) {
11206fe57b42Smillert 
11216fe57b42Smillert 				case 'c':
11226fe57b42Smillert 					mult = lp->d_secpercyl;
11236fe57b42Smillert 					buf[--n] = '\0';
11246fe57b42Smillert 					break;
11256fe57b42Smillert 				case 'b':
11266fe57b42Smillert 					mult = -lp->d_secsize;
11276fe57b42Smillert 					buf[--n] = '\0';
11286fe57b42Smillert 					break;
11296fe57b42Smillert 				case 'k':
11306fe57b42Smillert 					mult = 1024 / lp->d_secsize;
11316fe57b42Smillert 					buf[--n] = '\0';
11326fe57b42Smillert 					break;
11336fe57b42Smillert 				case 'm':
11346fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
11356fe57b42Smillert 					buf[--n] = '\0';
11366fe57b42Smillert 					break;
11371a51a1eeSmillert 				case 'g':
11381a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
11391a51a1eeSmillert 					buf[--n] = '\0';
11401a51a1eeSmillert 					break;
11416fe57b42Smillert 				}
114296a888c6Smillert 			}
11436fe57b42Smillert 
11446fe57b42Smillert 			/* Did they give us an operator? */
11456fe57b42Smillert 			p = &buf[0];
11466fe57b42Smillert 			if (*p == '+' || *p == '-')
11476fe57b42Smillert 				operator = *p++;
11486fe57b42Smillert 
11496fe57b42Smillert 			endptr = p;
115096a888c6Smillert 			errno = 0;
115196a888c6Smillert 			d = strtod(p, &endptr);
115296a888c6Smillert 			if (errno == ERANGE)
115396a888c6Smillert 				rval = UINT_MAX;	/* too big/small */
115496a888c6Smillert 			else if (*endptr != '\0') {
11556fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
11566fe57b42Smillert 				rval = UINT_MAX;
11576fe57b42Smillert 			} else {
115896a888c6Smillert 				/* XXX - should check for overflow */
115996a888c6Smillert 				if (mult > 0)
116096a888c6Smillert 					rval = d * mult;
116196a888c6Smillert 				else
116296a888c6Smillert 					/* Negative mult means divide (fancy) */
116396a888c6Smillert 					rval = d / (-mult);
11646fe57b42Smillert 
116596a888c6Smillert 				/* Apply the operator */
11666fe57b42Smillert 				if (operator == '+')
11676fe57b42Smillert 					rval += oval;
11686fe57b42Smillert 				else if (operator == '-')
11696fe57b42Smillert 					rval = oval - rval;
11706fe57b42Smillert 			}
11716fe57b42Smillert 		}
11726fe57b42Smillert 	}
11736fe57b42Smillert 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
1174dbffb156Smillert #ifndef CYLCHECK
117596a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
1176dbffb156Smillert 		if (mult != 1)
1177dbffb156Smillert #endif
1178dbffb156Smillert 		{
1179dbffb156Smillert 			u_int32_t cyls;
1180dbffb156Smillert 
1181dbffb156Smillert 			/* If we round up past the end, round down instead */
11826fe57b42Smillert 			cyls = (u_int32_t)((rval / (double)lp->d_secpercyl)
11836fe57b42Smillert 			    + 0.5);
11844b9a3bdaSmillert 			if (cyls != 0 && lp->d_secpercyl != 0) {
11854b9a3bdaSmillert 				if ((cyls * lp->d_secpercyl) - offset > maxval)
1186dbffb156Smillert 					cyls--;
1187dbffb156Smillert 
11884b9a3bdaSmillert 				if (rval != (cyls * lp->d_secpercyl) - offset) {
11894b9a3bdaSmillert 					rval = (cyls * lp->d_secpercyl) - offset;
11906fe57b42Smillert 					printf("Rounding to nearest cylinder: %u\n",
11916fe57b42Smillert 					    rval);
11926fe57b42Smillert 				}
11936fe57b42Smillert 			}
11946fe57b42Smillert 		}
11954b9a3bdaSmillert 	}
11966fe57b42Smillert 
11976fe57b42Smillert 	return(rval);
11986fe57b42Smillert }
11996fe57b42Smillert 
12006fe57b42Smillert /*
12016fe57b42Smillert  * Check for partition overlap in lp and prompt the user
12026fe57b42Smillert  * to resolve the overlap if any is found.  Returns 1
12036fe57b42Smillert  * if unable to resolve, else 0.
12046fe57b42Smillert  */
12056fe57b42Smillert int
12066fe57b42Smillert has_overlap(lp, freep, resolve)
12076fe57b42Smillert 	struct disklabel *lp;
12086fe57b42Smillert 	u_int32_t *freep;
12096fe57b42Smillert 	int resolve;
12106fe57b42Smillert {
12116fe57b42Smillert 	struct partition **spp;
12126fe57b42Smillert 	u_int16_t npartitions;
1213e6aa8bafSmillert 	int c, i, j;
1214e6aa8bafSmillert 	char buf[BUFSIZ];
12156fe57b42Smillert 
1216a7e61405Smillert 	/* Get a sorted list of the partitions */
1217a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
12186fe57b42Smillert 
12199afbe9eeSmillert 	if (npartitions < RAW_PART) {
1220a7e61405Smillert 		(void)free(spp);
12216fe57b42Smillert 		return(0);			/* nothing to do */
12226fe57b42Smillert 	}
12236fe57b42Smillert 
12246fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12256fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
12266fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
12276fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
12286fe57b42Smillert 			if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) {
122996a888c6Smillert 				/* Don't print, just return */
123096a888c6Smillert 				if (resolve == -1) {
123196a888c6Smillert 					(void)free(spp);
123296a888c6Smillert 					return(1);
123396a888c6Smillert 				}
123496a888c6Smillert 
12356fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
12366fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
12376fe57b42Smillert 				    / sizeof(**spp);
12386fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
12396fe57b42Smillert 				    / sizeof(**spp);
12406fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
12416fe57b42Smillert 				    'a' + i, 'a' + j);
12426fe57b42Smillert 				puts("         size   offset    fstype   [fsize bsize   cpg]");
1243bd6726faSmillert 				display_partition(stdout, lp, NULL, i, 0, 0);
1244bd6726faSmillert 				display_partition(stdout, lp, NULL, j, 0, 0);
12456fe57b42Smillert 
12466fe57b42Smillert 				/* Did they ask us to resolve it ourselves? */
124796a888c6Smillert 				if (resolve != 1) {
1248f0b4d0a9Smillert 					(void)free(spp);
12496fe57b42Smillert 					return(1);
1250f0b4d0a9Smillert 				}
12516fe57b42Smillert 
1252e6aa8bafSmillert 				/* Get partition to disable or ^D */
1253e6aa8bafSmillert 				do {
1254616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
12556fe57b42Smillert 					    'a' + i, 'a' + j);
1256e6aa8bafSmillert 					buf[0] = '\0';
1257616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1258616cd1c4Smillert 						putchar('\n');
1259e6aa8bafSmillert 						return(1);	/* ^D */
1260616cd1c4Smillert 					}
1261e6aa8bafSmillert 					c = buf[0] - 'a';
1262e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1263e6aa8bafSmillert 				    c != i && c != j);
1264e6aa8bafSmillert 
1265e6aa8bafSmillert 				/* Mark the selected one as unused */
12666fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
12676fe57b42Smillert 				*freep += lp->d_partitions[c].p_size;
1268e6aa8bafSmillert 				(void)free(spp);
1269e6aa8bafSmillert 				return(has_overlap(lp, freep, resolve));
12706fe57b42Smillert 			}
12716fe57b42Smillert 		}
12726fe57b42Smillert 	}
1273f0b4d0a9Smillert 
1274f0b4d0a9Smillert 	(void)free(spp);
1275e6aa8bafSmillert 	return(0);
12766fe57b42Smillert }
12776fe57b42Smillert 
12786fe57b42Smillert void
12796fe57b42Smillert edit_parms(lp, freep)
12806fe57b42Smillert 	struct disklabel *lp;
12816fe57b42Smillert 	u_int32_t *freep;
12826fe57b42Smillert {
12836fe57b42Smillert 	char *p;
12846fe57b42Smillert 	u_int32_t ui;
128596a888c6Smillert 	struct disklabel oldlabel = *lp;
12866fe57b42Smillert 
1287ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
12886fe57b42Smillert 
12890f820bbbSmillert 	/* disk type */
12900f820bbbSmillert 	for (;;) {
1291c33fcabaSmillert 		p = getstring("disk type",
129241282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
129341282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
129496a888c6Smillert 		if (p == NULL) {
129596a888c6Smillert 			fputs("Command aborted\n", stderr);
129696a888c6Smillert 			return;
129796a888c6Smillert 		}
129841282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
129941282a2aSmillert 			ui = DTYPE_ESDI;
130041282a2aSmillert 		else
130141282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
130241282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13030f820bbbSmillert 				;
13040f820bbbSmillert 		if (ui < DKMAXTYPES) {
13050f820bbbSmillert 			break;
13060f820bbbSmillert 		} else {
13070f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13080f820bbbSmillert 			fputs("Valid types are: ", stdout);
13090f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13100f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13110f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13120f820bbbSmillert 					fputs(", ", stdout);
13130f820bbbSmillert 			}
13140f820bbbSmillert 			putchar('\n');
13150f820bbbSmillert 		}
13160f820bbbSmillert 	}
13170f820bbbSmillert 	lp->d_type = ui;
13180f820bbbSmillert 
13196fe57b42Smillert 	/* pack/label id */
1320c33fcabaSmillert 	p = getstring("label name",
13216fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13226fe57b42Smillert 	    lp->d_packname);
132396a888c6Smillert 	if (p == NULL) {
132496a888c6Smillert 		fputs("Command aborted\n", stderr);
132596a888c6Smillert 		*lp = oldlabel;		/* undo damage */
132696a888c6Smillert 		return;
132796a888c6Smillert 	}
13286fe57b42Smillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1);
13296fe57b42Smillert 	lp->d_packname[sizeof(lp->d_packname) - 1] = '\0';
13306fe57b42Smillert 
13316fe57b42Smillert 	/* sectors/track */
13326fe57b42Smillert 	for (;;) {
13336fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
13346fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
13354b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
133696a888c6Smillert 		if (ui == UINT_MAX - 1) {
133796a888c6Smillert 			fputs("Command aborted\n", stderr);
133896a888c6Smillert 			*lp = oldlabel;		/* undo damage */
133996a888c6Smillert 			return;
134096a888c6Smillert 		} if (ui == UINT_MAX)
13416fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13426fe57b42Smillert 		else
13436fe57b42Smillert 			break;
13446fe57b42Smillert 	}
13456fe57b42Smillert 	lp->d_nsectors = ui;
13466fe57b42Smillert 
13476fe57b42Smillert 	/* tracks/cylinder */
13486fe57b42Smillert 	for (;;) {
13496fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
13506fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
13514b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
135296a888c6Smillert 		if (ui == UINT_MAX - 1) {
135396a888c6Smillert 			fputs("Command aborted\n", stderr);
135496a888c6Smillert 			*lp = oldlabel;		/* undo damage */
135596a888c6Smillert 			return;
135696a888c6Smillert 		} else if (ui == UINT_MAX)
13576fe57b42Smillert 			fputs("Invalid entry\n", stderr);
13586fe57b42Smillert 		else
13596fe57b42Smillert 			break;
13606fe57b42Smillert 	}
13616fe57b42Smillert 	lp->d_ntracks = ui;
13626fe57b42Smillert 
13636fe57b42Smillert 	/* sectors/cylinder */
1364148b6188Smillert 	for (;;) {
1365148b6188Smillert 		ui = getuint(lp, 0, "sectors/cylinder",
1366148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
13674b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
13684b9a3bdaSmillert 		    0, 0);
136996a888c6Smillert 		if (ui == UINT_MAX - 1) {
137096a888c6Smillert 			fputs("Command aborted\n", stderr);
137196a888c6Smillert 			*lp = oldlabel;		/* undo damage */
137296a888c6Smillert 			return;
137396a888c6Smillert 		} else if (ui == UINT_MAX)
1374148b6188Smillert 			fputs("Invalid entry\n", stderr);
1375148b6188Smillert 		else
1376148b6188Smillert 			break;
1377148b6188Smillert 	}
1378148b6188Smillert 	lp->d_secpercyl = ui;
13796fe57b42Smillert 
13806fe57b42Smillert 	/* number of cylinders */
13816fe57b42Smillert 	for (;;) {
13826fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
13836fe57b42Smillert 		    "The total number of cylinders on the disk.",
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);
13916fe57b42Smillert 		else
13926fe57b42Smillert 			break;
13936fe57b42Smillert 	}
13946fe57b42Smillert 	lp->d_ncylinders = ui;
13956fe57b42Smillert 
13966fe57b42Smillert 	/* total sectors */
13976fe57b42Smillert 	for (;;) {
13986fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
13996fe57b42Smillert 		    "The total number of sectors on the disk.",
14006fe57b42Smillert 		    lp->d_secperunit ? lp->d_secperunit :
14016fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders,
14024b9a3bdaSmillert 		    lp->d_ncylinders * lp->d_ncylinders, 0, 0);
140396a888c6Smillert 		if (ui == UINT_MAX - 1) {
140496a888c6Smillert 			fputs("Command aborted\n", stderr);
140596a888c6Smillert 			*lp = oldlabel;		/* undo damage */
140696a888c6Smillert 			return;
140796a888c6Smillert 		} else if (ui == UINT_MAX)
14086fe57b42Smillert 			fputs("Invalid entry\n", stderr);
140996a888c6Smillert 		else if (ui > lp->d_secperunit &&
141096a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14116fe57b42Smillert 			/* grow free count */
14126fe57b42Smillert 			*freep += ui - lp->d_secperunit;
1413f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1414f98aebd4Smillert 			    "partition.");
14156fe57b42Smillert 			break;
141696a888c6Smillert 		} else if (ui < lp->d_secperunit &&
141796a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14186fe57b42Smillert 			/* shrink free count */
14196fe57b42Smillert 			if (lp->d_secperunit - ui > *freep)
14206fe57b42Smillert 				fprintf(stderr,
14216fe57b42Smillert 				    "Not enough free space to shrink by %u "
14226fe57b42Smillert 				    "sectors (only %u sectors left)\n",
14236fe57b42Smillert 				    lp->d_secperunit - ui, *freep);
14246fe57b42Smillert 			else {
14256fe57b42Smillert 				*freep -= lp->d_secperunit - ui;
14266fe57b42Smillert 				break;
14276fe57b42Smillert 			}
14286fe57b42Smillert 		} else
14296fe57b42Smillert 			break;
14306fe57b42Smillert 	}
143196a888c6Smillert 	/* Adjust ending_sector if necesary. */
143296a888c6Smillert 	if (ending_sector > ui)
143396a888c6Smillert 		ending_sector = ui;
14346fe57b42Smillert 	lp->d_secperunit = ui;
14356fe57b42Smillert 
14366fe57b42Smillert 	/* rpm */
14376fe57b42Smillert 	for (;;) {
14386fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1439a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
14404b9a3bdaSmillert 		  lp->d_rpm, lp->d_rpm, 0, 0);
144196a888c6Smillert 		if (ui == UINT_MAX - 1) {
144296a888c6Smillert 			fputs("Command aborted\n", stderr);
144396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
144496a888c6Smillert 			return;
144596a888c6Smillert 		} else if (ui == UINT_MAX)
14466fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14476fe57b42Smillert 		else
14486fe57b42Smillert 			break;
14496fe57b42Smillert 	}
14506fe57b42Smillert 	lp->d_rpm = ui;
1451440b1d70Smillert 
1452440b1d70Smillert 	/* interleave */
1453440b1d70Smillert 	for (;;) {
1454440b1d70Smillert 		ui = getuint(lp, 0, "interleave",
1455440b1d70Smillert 		  "The physical sector interleave, set when formatting.  Almost always 1.",
14564b9a3bdaSmillert 		  lp->d_interleave, lp->d_interleave, 0, 0);
1457440b1d70Smillert 		if (ui == UINT_MAX - 1) {
1458440b1d70Smillert 			fputs("Command aborted\n", stderr);
1459440b1d70Smillert 			*lp = oldlabel;		/* undo damage */
1460440b1d70Smillert 			return;
1461440b1d70Smillert 		} else if (ui == UINT_MAX || ui == 0)
1462440b1d70Smillert 			fputs("Invalid entry\n", stderr);
1463440b1d70Smillert 		else
1464440b1d70Smillert 			break;
1465440b1d70Smillert 	}
1466440b1d70Smillert 	lp->d_interleave = ui;
14676fe57b42Smillert }
1468a7e61405Smillert 
1469a7e61405Smillert struct partition **
1470a7e61405Smillert sort_partitions(lp, npart)
1471a7e61405Smillert 	struct disklabel *lp;
1472a7e61405Smillert 	u_int16_t *npart;
1473a7e61405Smillert {
1474a7e61405Smillert 	u_int16_t npartitions;
1475a7e61405Smillert 	struct partition **spp;
1476a7e61405Smillert 	int i;
1477a7e61405Smillert 
1478a7e61405Smillert 	/* How many "real" partitions do we have? */
1479a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1480a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1481a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1482a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1483a7e61405Smillert 			npartitions++;
1484a7e61405Smillert 	}
148596a888c6Smillert 	if (npartitions == 0) {
148696a888c6Smillert 		*npart = 0;
148796a888c6Smillert 		return(NULL);
148896a888c6Smillert 	}
1489a7e61405Smillert 
1490a7e61405Smillert 	/* Create an array of pointers to the partition data */
1491a7e61405Smillert 	if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL)
1492a7e61405Smillert 		errx(4, "out of memory");
1493a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1494a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1495a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1496a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1497a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1498a7e61405Smillert 	}
1499a7e61405Smillert 
1500a7e61405Smillert 	/*
1501a7e61405Smillert 	 * Sort the partitions based on starting offset.
1502a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1503a7e61405Smillert 	 */
1504a7e61405Smillert 	if (npartitions > 1)
1505a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1506a7e61405Smillert 		    partition_cmp))
1507a7e61405Smillert 			err(4, "failed to sort partition table");
1508a7e61405Smillert 
1509a7e61405Smillert 	*npart = npartitions;
1510a7e61405Smillert 	return(spp);
1511a7e61405Smillert }
15120f820bbbSmillert 
15130f820bbbSmillert /*
15140f820bbbSmillert  * Get a valid disk type if necessary.
15150f820bbbSmillert  */
15160f820bbbSmillert void
1517803ff7d5Smillert getdisktype(lp, banner, dev)
15180f820bbbSmillert 	struct disklabel *lp;
15190f820bbbSmillert 	char *banner;
1520803ff7d5Smillert 	char *dev;
15210f820bbbSmillert {
15220f820bbbSmillert 	int i;
1523803ff7d5Smillert 	char *s, *def = "SCSI";
1524803ff7d5Smillert 	struct dtypes {
1525803ff7d5Smillert 		char *dev;
1526803ff7d5Smillert 		char *type;
1527803ff7d5Smillert 	} dtypes[] = {
1528c33fcabaSmillert 		{ "sd",   "SCSI" },
1529c33fcabaSmillert 		{ "rz",   "SCSI" },
1530c33fcabaSmillert 		{ "wd",   "IDE" },
1531c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1532c33fcabaSmillert 		{ "xd",   "SMD" },
1533c33fcabaSmillert 		{ "xy",   "SMD" },
1534c33fcabaSmillert 		{ "hd",   "HP-IB" },
1535c33fcabaSmillert 		{ "ccd",  "CCD" },
1536c33fcabaSmillert 		{ "vnd",  "VND" },
1537c33fcabaSmillert 		{ "svnd", "VND" },
1538c33fcabaSmillert 		{ NULL,   NULL }
1539803ff7d5Smillert 	};
1540803ff7d5Smillert 
1541803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1542803ff7d5Smillert 		if (*s == 'r')
1543803ff7d5Smillert 			s++;
1544803ff7d5Smillert 		i = strcspn(s, "0123456789");
1545803ff7d5Smillert 		s[i] = '\0';
1546803ff7d5Smillert 		dev = s;
1547803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1548803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1549803ff7d5Smillert 				def = dtypes[i].type;
1550803ff7d5Smillert 				break;
1551803ff7d5Smillert 			}
1552803ff7d5Smillert 		}
1553803ff7d5Smillert 	}
15540f820bbbSmillert 
15550f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15560f820bbbSmillert 		puts(banner);
15570f820bbbSmillert 		puts("Possible values are:");
1558eb5dd924Sderaadt 		printf("\"IDE\", ");
15590f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15600f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15610f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15620f820bbbSmillert 				fputs(", ", stdout);
15630f820bbbSmillert 		}
15640f820bbbSmillert 		putchar('\n');
15650f820bbbSmillert 
15660f820bbbSmillert 		for (;;) {
1567c33fcabaSmillert 			s = getstring("Disk type",
1568803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1569803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
157096a888c6Smillert 			if (s == NULL)
157196a888c6Smillert 				continue;
15725b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
15735b412421Smillert 				lp->d_type = DTYPE_ESDI;
15745b412421Smillert 				return;
15755b412421Smillert 			}
15760f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
15770f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
15780f820bbbSmillert 					lp->d_type = i;
15790f820bbbSmillert 					return;
15800f820bbbSmillert 				}
15810f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
15820f820bbbSmillert 			fputs("Valid types are: ", stdout);
15830f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
15840f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
15850f820bbbSmillert 				if (i < DKMAXTYPES - 1)
15860f820bbbSmillert 					fputs(", ", stdout);
15870f820bbbSmillert 			}
15880f820bbbSmillert 			putchar('\n');
15890f820bbbSmillert 		}
15900f820bbbSmillert 	}
15910f820bbbSmillert }
159296a888c6Smillert 
159396a888c6Smillert /*
159496a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
159596a888c6Smillert  * from the user.
15964793b14cSmillert  * XXX - should mention MBR values if DOSLABEL
159796a888c6Smillert  */
159896a888c6Smillert void
1599e8e8bdb7Sart set_bounds(lp, freep)
160096a888c6Smillert 	struct disklabel *lp;
1601e8e8bdb7Sart 	u_int32_t *freep;
160296a888c6Smillert {
160396a888c6Smillert 	u_int32_t ui, start_temp;
160496a888c6Smillert 
160596a888c6Smillert 	/* Starting sector */
160696a888c6Smillert 	do {
160796a888c6Smillert 		ui = getuint(lp, 0, "Starting sector",
160896a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
16094b9a3bdaSmillert 		  starting_sector, lp->d_secperunit, 0, 0);
161096a888c6Smillert 		if (ui == UINT_MAX - 1) {
161196a888c6Smillert 			fputs("Command aborted\n", stderr);
161296a888c6Smillert 			return;
161396a888c6Smillert 		}
161496a888c6Smillert 	} while (ui >= lp->d_secperunit);
161596a888c6Smillert 	start_temp = ui;
161696a888c6Smillert 
16174793b14cSmillert 	/* Size */
161896a888c6Smillert 	do {
1619f98aebd4Smillert 		ui = getuint(lp, 0, "Size ('*' for entire disk)",
1620f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1621f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
16224b9a3bdaSmillert 		  lp->d_secperunit - start_temp, 0, 0);
162396a888c6Smillert 		if (ui == UINT_MAX - 1) {
162496a888c6Smillert 			fputs("Command aborted\n", stderr);
162596a888c6Smillert 			return;
162696a888c6Smillert 		}
1627f98aebd4Smillert 	} while (ui > lp->d_secperunit - start_temp);
16284793b14cSmillert 	ending_sector = start_temp + ui;
162996a888c6Smillert 	starting_sector = start_temp;
1630e8e8bdb7Sart 
1631e8e8bdb7Sart 	/* Recalculate the free sectors */
1632c0bdc608Smillert 	editor_countfree(lp, freep);
163396a888c6Smillert }
163496a888c6Smillert 
163596a888c6Smillert /*
163696a888c6Smillert  * Return a list of the "chunks" of free space available
163796a888c6Smillert  */
163896a888c6Smillert struct diskchunk *
163996a888c6Smillert free_chunks(lp)
164096a888c6Smillert 	struct disklabel *lp;
164196a888c6Smillert {
164296a888c6Smillert 	u_int16_t npartitions;
164396a888c6Smillert 	struct partition **spp;
164496a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
164596a888c6Smillert 	int i, numchunks;
164696a888c6Smillert 
164796a888c6Smillert 	/* Sort the partitions based on offset */
164896a888c6Smillert 	spp = sort_partitions(lp, &npartitions);
164996a888c6Smillert 
165096a888c6Smillert 	/* If there are no partitions, it's all free. */
165196a888c6Smillert 	if (spp == NULL) {
16522d8451b0Smillert 		chunks[0].start = starting_sector;
165396a888c6Smillert 		chunks[0].stop = ending_sector;
165496a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
165596a888c6Smillert 		return(chunks);
165696a888c6Smillert 	}
165796a888c6Smillert 
165896a888c6Smillert 	/* Find chunks of free space */
165996a888c6Smillert 	numchunks = 0;
166096a888c6Smillert 	if (spp && spp[0]->p_offset > 0) {
16612d8451b0Smillert 		chunks[0].start = starting_sector;
166296a888c6Smillert 		chunks[0].stop = spp[0]->p_offset;
166396a888c6Smillert 		numchunks++;
166496a888c6Smillert 	}
166596a888c6Smillert 	for (i = 0; i < npartitions; i++) {
166696a888c6Smillert 		if (i + 1 < npartitions) {
166796a888c6Smillert 			if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) {
166896a888c6Smillert 				chunks[numchunks].start =
166996a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
167096a888c6Smillert 				chunks[numchunks].stop = spp[i+1]->p_offset;
167196a888c6Smillert 				numchunks++;
167296a888c6Smillert 			}
167396a888c6Smillert 		} else {
167496a888c6Smillert 			/* Last partition */
167565ce672dScsapuntz 			if (spp[i]->p_offset + spp[i]->p_size < ending_sector) {
167696a888c6Smillert 
167796a888c6Smillert 				chunks[numchunks].start =
167896a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
167965ce672dScsapuntz 				chunks[numchunks].stop = ending_sector;
168096a888c6Smillert 				numchunks++;
168196a888c6Smillert 			}
168296a888c6Smillert 		}
168396a888c6Smillert 	}
168496a888c6Smillert 
168596a888c6Smillert 	/* Terminate and return */
168696a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
168796a888c6Smillert 	(void)free(spp);
168896a888c6Smillert 	return(chunks);
168996a888c6Smillert }
16904793b14cSmillert 
16914793b14cSmillert /*
16924793b14cSmillert  * What is the OpenBSD portion of the disk?  Uses the MBR if applicable.
16934793b14cSmillert  */
16944793b14cSmillert void
16959785f718Smillert find_bounds(lp, bios_lp)
16964793b14cSmillert 	struct disklabel *lp;
1697d09f3941Smillert 	struct disklabel *bios_lp;
16984793b14cSmillert {
1699d09f3941Smillert 	struct partition *pp = &lp->d_partitions[RAW_PART];
17004793b14cSmillert 
17014793b14cSmillert 	/* Defaults */
17024793b14cSmillert 	/* XXX - reserve a cylinder for hp300? */
17034793b14cSmillert 	starting_sector = 0;
17044793b14cSmillert 	ending_sector = lp->d_secperunit;
17054793b14cSmillert 
17064793b14cSmillert #ifdef DOSLABEL
1707528915f5Smillert 	/*
1708d09f3941Smillert 	 * If we have an MBR, use values from the {Open,Free,Net}BSD partition
1709528915f5Smillert 	 */
1710d09f3941Smillert 	if (dosdp) {
1711fd29f560Sderaadt 	    if (dosdp->dp_typ == DOSPTYP_OPENBSD ||
1712aaa7b57dSderaadt 		    dosdp->dp_typ == DOSPTYP_FREEBSD ||
1713fd29f560Sderaadt 		    dosdp->dp_typ == DOSPTYP_NETBSD) {
1714528915f5Smillert 			u_int32_t i, new_end;
1715528915f5Smillert 
1716d09f3941Smillert 			/* Set start and end based on fdisk partition bounds */
17174793b14cSmillert 			starting_sector = get_le(&dosdp->dp_start);
17184793b14cSmillert 			ending_sector = starting_sector + get_le(&dosdp->dp_size);
1719528915f5Smillert 
1720528915f5Smillert 			/*
1721d09f3941Smillert 			 * If the ending sector of the BSD fdisk partition
1722d09f3941Smillert 			 * is equal to the ending sector of the BIOS geometry
1723d09f3941Smillert 			 * but the real sector count > BIOS sector count,
1724d09f3941Smillert 			 * adjust the bounds accordingly.  We do this because
1725d09f3941Smillert 			 * the BIOS geometry is limited to disks of ~4gig.
1726d09f3941Smillert 			 */
1727d09f3941Smillert 			if (bios_lp && ending_sector == bios_lp->d_secperunit &&
1728d09f3941Smillert 			    lp->d_secperunit > bios_lp->d_secperunit)
1729d09f3941Smillert 				ending_sector = lp->d_secperunit;
1730d09f3941Smillert 
1731d09f3941Smillert 			/*
1732d09f3941Smillert 			 * If there are any BSD or SWAP partitions beyond
1733d09f3941Smillert 			 * ending_sector we extend ending_sector to include
1734d09f3941Smillert 			 * them.  This is done because the BIOS geometry is
1735d09f3941Smillert 			 * generally different from the disk geometry.
1736528915f5Smillert 			 */
1737528915f5Smillert 			for (i = new_end = 0; i < lp->d_npartitions; i++) {
1738528915f5Smillert 				pp = &lp->d_partitions[i];
1739528915f5Smillert 				if ((pp->p_fstype == FS_BSDFFS ||
1740528915f5Smillert 				    pp->p_fstype == FS_SWAP) &&
1741528915f5Smillert 				    pp->p_size + pp->p_offset > new_end)
1742528915f5Smillert 					new_end = pp->p_size + pp->p_offset;
1743528915f5Smillert 			}
1744528915f5Smillert 			if (new_end > ending_sector)
1745528915f5Smillert 				ending_sector = new_end;
1746d09f3941Smillert 		} else {
1747d09f3941Smillert 			/* Don't trounce the MBR */
17489785f718Smillert 			starting_sector = 63;
1749d09f3941Smillert 		}
1750d09f3941Smillert 
1751508086e9Smillert 		printf("\nTreating sectors %u-%u as the OpenBSD portion of the "
17524793b14cSmillert 		    "disk.\nYou can use the 'b' command to change this.\n",
17534793b14cSmillert 		    starting_sector, ending_sector);
17544793b14cSmillert 	}
1755d3f02056Smillert #elif (NUMBOOT == 1)
1756d3f02056Smillert 	/* Boot blocks take up the first cylinder */
1757d3f02056Smillert 	starting_sector = lp->d_secpercyl;
1758d3f02056Smillert 	printf("\nReserving the first data cylinder for boot blocks.\n"
1759d3f02056Smillert 	    "You can use the 'b' command to change this.\n");
17604793b14cSmillert #endif
17614793b14cSmillert }
1762c0bdc608Smillert 
1763c0bdc608Smillert /*
1764c0bdc608Smillert  * Calculate free space.
1765c0bdc608Smillert  */
1766c0bdc608Smillert void
1767c0bdc608Smillert editor_countfree(lp, freep)
1768c0bdc608Smillert 	struct disklabel *lp;
1769c0bdc608Smillert 	u_int32_t *freep;
1770c0bdc608Smillert {
1771c0bdc608Smillert 	struct partition *pp;
1772c0bdc608Smillert 	int i;
1773c0bdc608Smillert 
1774c0bdc608Smillert 	*freep = ending_sector - starting_sector;
1775c0bdc608Smillert 	for (i = 0; i < lp->d_npartitions; i++) {
1776c0bdc608Smillert 		    pp = &lp->d_partitions[i];
1777c0bdc608Smillert 		    if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
1778c0bdc608Smillert 			pp->p_size > 0 &&
1779c0bdc608Smillert 			pp->p_offset + pp->p_size <= ending_sector &&
1780c0bdc608Smillert 			pp->p_offset >= starting_sector)
1781c0bdc608Smillert 			*freep -= pp->p_size;
1782c0bdc608Smillert 	}
1783c0bdc608Smillert }
1784617e6e4aSmillert 
1785617e6e4aSmillert void
1786617e6e4aSmillert editor_help(arg)
1787617e6e4aSmillert 	char *arg;
1788617e6e4aSmillert {
1789617e6e4aSmillert 
1790617e6e4aSmillert 	/* XXX - put these strings in a table instead? */
1791617e6e4aSmillert 	switch (*arg) {
1792617e6e4aSmillert 	case 'p':
1793617e6e4aSmillert 		puts(
1794617e6e4aSmillert "The 'p' command prints the current disk label.  By default, it prints the\n"
1795617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1796617e6e4aSmillert "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1797617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1798617e6e4aSmillert 		break;
1799617e6e4aSmillert 	case 'M':
1800617e6e4aSmillert 		puts(
18019afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n"
1802508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n"
1803508086e9Smillert "not set.  It is especially useful during install when the normal system\n"
1804508086e9Smillert "manual is not available.\n");
1805617e6e4aSmillert 		break;
1806617e6e4aSmillert 	case 'e':
1807617e6e4aSmillert 		puts(
1808617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters.  These include\n"
1809617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n"
1810617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n"
1811617e6e4aSmillert "type, and a descriptive label string.  You should not change these unless\n"
1812617e6e4aSmillert "you know what you are doing\n");
1813617e6e4aSmillert 		break;
1814617e6e4aSmillert 	case 'a':
1815617e6e4aSmillert 		puts(
1816617e6e4aSmillert "The 'a' command adds new partitions to the disk.  It takes as an optional\n"
1817617e6e4aSmillert "argument the partition letter to add.  If you do not specify a partition\n"
1818617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n"
1819617e6e4aSmillert "default answer\n");
1820617e6e4aSmillert 		break;
1821617e6e4aSmillert 	case 'b':
1822617e6e4aSmillert 		puts(
1823617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n"
1824617e6e4aSmillert "the disk.  This is only useful on disks with an fdisk partition.  By default,\n"
1825617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n"
1826617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition.  You should only change\n"
1827617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n"
1828617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be.  You\n"
1829617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n"
1830617e6e4aSmillert "(minus the starting sector).  Use this option with care; if you extend the\n"
1831617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n"
1832617e6e4aSmillert "corrupt the other operating system's data.\n");
1833617e6e4aSmillert 		break;
1834617e6e4aSmillert 	case 'c':
1835617e6e4aSmillert 		puts(
1836617e6e4aSmillert "The 'c' command is used to change the size of an existing partition.  It\n"
1837617e6e4aSmillert "takes as an optional argument the partition letter to change.  If you do not\n"
1838617e6e4aSmillert "specify a partition letter, you will be prompted for one.  You may add a '+'\n"
1839617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n"
1840617e6e4aSmillert "instead of entering an absolute value.  You may also use a suffix to indicate\n"
1841617e6e4aSmillert "the units the values is in terms of.  Possible suffixes are 'b' for bytes,\n"
1842617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n"
1843617e6e4aSmillert "no suffix for sectors (usually 512 bytes).  You may also enter '*' to change\n"
1844617e6e4aSmillert "the size to be the total number of free sectors remaining.\n");
1845617e6e4aSmillert 		break;
18469afbe9eeSmillert 	case 'D':
18479afbe9eeSmillert 		puts(
18489afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n"
18499afbe9eeSmillert "by the disk itself.  This similates the case where there is no disk label.\n");
18509afbe9eeSmillert 		break;
1851617e6e4aSmillert 	case 'd':
1852617e6e4aSmillert 		puts(
1853617e6e4aSmillert "The 'd' command is used to delete an existing partition.  It takes as an\n"
1854617e6e4aSmillert "optional argument the partition letter to change.  If you do not specify a\n"
1855617e6e4aSmillert "partition letter, you will be prompted for one.  You may not delete the ``c''\n"
1856617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n"
1857617e6e4aSmillert "it does not take up any space).\n");
1858617e6e4aSmillert 		break;
1859c33fcabaSmillert 	case 'g':
1860c33fcabaSmillert 		puts(
1861c33fcabaSmillert "The 'g' command is used select which disk geometry to use, the disk, BIOS, or\n"
1862c33fcabaSmillert "user geometry.  It takes as an optional argument ``d'', ``b'', or ``u''.  If \n"
1863c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n");
1864c33fcabaSmillert 		break;
1865617e6e4aSmillert 	case 'm':
1866617e6e4aSmillert 		puts(
1867617e6e4aSmillert "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"
1868617e6e4aSmillert "partition letter, you will be prompted for one.  This option allows the user\n"
1869617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n"
1870617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n"
1871617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n");
1872617e6e4aSmillert 		break;
1873bd6726faSmillert 	case 'n':
1874bd6726faSmillert 		puts(
1875fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n"
1876bd6726faSmillert "It takes as an optional argument the partition letter to name.  If you do\n"
1877bd6726faSmillert "not specify a partition letter, you will be prompted for one.  This option\n"
1878bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n");
1879bd6726faSmillert 		break;
1880617e6e4aSmillert 	case 'r':
1881617e6e4aSmillert 		puts(
1882617e6e4aSmillert "The 'r' command is used to recalculate the free space available.  This option\n"
1883617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n"
1884617e6e4aSmillert "disklabel gets confused.\n");
1885617e6e4aSmillert 		break;
1886617e6e4aSmillert 	case 'u':
1887617e6e4aSmillert 		puts(
1888617e6e4aSmillert "The 'u' command will undo (or redo) the last change.  Entering 'u' once will\n"
1889617e6e4aSmillert "undo your last change.  Entering it again will restore the change.\n");
1890617e6e4aSmillert 		break;
1891617e6e4aSmillert 	case 's':
1892617e6e4aSmillert 		puts(
1893617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n"
1894617e6e4aSmillert "(suitable for loading via disklabel's [-R] option).  It takes as an optional\n"
1895617e6e4aSmillert "argument the filename to save the label to.  If you do not specify a filename,\n"
1896617e6e4aSmillert "you will be prompted for one.\n");
1897617e6e4aSmillert 		break;
1898617e6e4aSmillert 	case 'w':
1899617e6e4aSmillert 		puts(
1900617e6e4aSmillert "The 'w' command will write the current label to disk.  This option will\n"
1901617e6e4aSmillert "commit any changes to the on-disk label.\n");
1902617e6e4aSmillert 		break;
1903617e6e4aSmillert 	case 'q':
1904617e6e4aSmillert 		puts(
1905617e6e4aSmillert "The 'q' command quits the label editor.  If any changes have been made you\n"
1906617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n");
1907617e6e4aSmillert 		break;
19089afbe9eeSmillert 	case 'X':
19099afbe9eeSmillert 		puts(
19109afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'.  By default,\n"
19119afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n"
19129afbe9eeSmillert "size on ffs partitions).\n");
19139afbe9eeSmillert 		break;
1914617e6e4aSmillert 	case 'x':
1915617e6e4aSmillert 		puts(
1916617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n"
1917617e6e4aSmillert "on-disk label.\n");
1918617e6e4aSmillert 		break;
19199afbe9eeSmillert 	case 'z':
19209afbe9eeSmillert 		puts(
19219afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n"
19229afbe9eeSmillert "partition.  The drive parameters are not changed.\n");
19239afbe9eeSmillert 		break;
1924617e6e4aSmillert 	default:
1925617e6e4aSmillert 		puts("Available commands:");
1926617e6e4aSmillert 		puts("\tp [unit]  - print label.");
1927617e6e4aSmillert 		puts("\tM         - show entire OpenBSD man page for disklabel.");
1928617e6e4aSmillert 		puts("\te         - edit drive parameters.");
1929617e6e4aSmillert 		puts("\ta [part]  - add new partition.");
1930617e6e4aSmillert 		puts("\tb         - set OpenBSD disk boundaries.");
1931617e6e4aSmillert 		puts("\tc [part]  - change partition size.");
1932617e6e4aSmillert 		puts("\td [part]  - delete partition.");
19339afbe9eeSmillert 		puts("\tD         - set label to default.");
1934c33fcabaSmillert 		puts("\tg [d|b]   - Use [d]isk or [b]ios geometry.");
1935617e6e4aSmillert 		puts("\tm [part]  - modify existing partition.");
1936bd6726faSmillert 		puts("\tn [part]  - set the mount point for a partition.");
1937617e6e4aSmillert 		puts("\tr         - recalculate free space.");
1938617e6e4aSmillert 		puts("\tu         - undo last change.");
1939617e6e4aSmillert 		puts("\ts [path]  - save label to file.");
1940617e6e4aSmillert 		puts("\tw         - write label to disk.");
1941617e6e4aSmillert 		puts("\tq         - quit and save changes.");
1942617e6e4aSmillert 		puts("\tx         - exit without saving changes.");
19432d8451b0Smillert 		puts("\tX         - toggle expert mode.");
19449afbe9eeSmillert 		puts("\tz         - zero out partition table.");
1945617e6e4aSmillert 		puts("\t? [cmnd]  - this message or command specific help.");
1946617e6e4aSmillert 		puts(
1947617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t"
1948617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t"
1949617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t"
1950617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n"
1951617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help.");
1952617e6e4aSmillert 		break;
1953617e6e4aSmillert 	}
1954617e6e4aSmillert }
1955bd6726faSmillert 
1956bd6726faSmillert char **
1957bd6726faSmillert mpcopy(to, from)
1958bd6726faSmillert 	char **to;
1959bd6726faSmillert 	char **from;
1960bd6726faSmillert {
1961bd6726faSmillert 	int i;
1962bd6726faSmillert 
1963bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1964bd6726faSmillert 		if (from[i] != NULL) {
1965bd6726faSmillert 			to[i] = realloc(to[i], strlen(from[i]) + 1);
1966bd6726faSmillert 			if (to[i] == NULL)
1967bd6726faSmillert 				errx(4, "out of memory");
1968bd6726faSmillert 			(void)strcpy(to[i], from[i]);
1969bd6726faSmillert 		} else if (to[i] != NULL) {
1970bd6726faSmillert 			free(to[i]);
1971bd6726faSmillert 			to[i] = NULL;
1972bd6726faSmillert 		}
1973bd6726faSmillert 	}
1974bd6726faSmillert 	return(to);
1975bd6726faSmillert }
1976bd6726faSmillert 
1977bd6726faSmillert int
1978bd6726faSmillert mpequal(mp1, mp2)
1979bd6726faSmillert 	char **mp1;
1980bd6726faSmillert 	char **mp2;
1981bd6726faSmillert {
1982bd6726faSmillert 	int i;
1983bd6726faSmillert 
1984bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1985bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1986bd6726faSmillert 			continue;
1987bd6726faSmillert 
1988bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1989bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1990bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1991bd6726faSmillert 			return(0);
1992bd6726faSmillert 	}
1993bd6726faSmillert 	return(1);
1994bd6726faSmillert }
1995bd6726faSmillert 
1996bd6726faSmillert int
1997bd6726faSmillert mpsave(lp, mp, cdev, fstabfile)
1998bd6726faSmillert 	struct disklabel *lp;
1999bd6726faSmillert 	char **mp;
2000bd6726faSmillert 	char *cdev;
2001bd6726faSmillert 	char *fstabfile;
2002bd6726faSmillert {
20035fea0b85Smillert 	int i, j, mpset;
2004bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
20053f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
2006bd6726faSmillert 	FILE *fp;
2007bd6726faSmillert 
20083f843443Smillert 	memset(&mi, 0, sizeof(mi));
20093f843443Smillert 
2010bd6726faSmillert 	for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) {
2011bd6726faSmillert 		if (mp[i] != NULL) {
20123f843443Smillert 			mi[i].mountpoint = mp[i];
20133f843443Smillert 			mi[i].partno = i;
2014bd6726faSmillert 			mpset = 1;
2015bd6726faSmillert 		}
2016bd6726faSmillert 	}
20173f843443Smillert 	/* Exit if there is nothing to do... */
2018bd6726faSmillert 	if (!mpset)
20193f843443Smillert 		return(0);
2020bd6726faSmillert 
2021bd6726faSmillert 	/* Convert cdev to bdev */
2022bd6726faSmillert 	if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 &&
2023bd6726faSmillert 	    cdev[sizeof(_PATH_DEV) - 1] == 'r') {
2024bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
2025bd6726faSmillert 		    &cdev[sizeof(_PATH_DEV)]);
2026bd6726faSmillert 	} else {
2027bd6726faSmillert 		if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r')
2028bd6726faSmillert 			return(1);
2029bd6726faSmillert 		*p = '\0';
2030bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1);
2031bd6726faSmillert 		*p = 'r';
2032bd6726faSmillert 	}
2033bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
2034bd6726faSmillert 
20353f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
20363f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
20373f843443Smillert 
2038bd6726faSmillert 	if ((fp = fopen(fstabfile, "w")) == NULL)
2039bd6726faSmillert 		return(1);
2040bd6726faSmillert 
20413f843443Smillert 	for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) {
20425fea0b85Smillert 		j =  mi[i].partno;
20435fea0b85Smillert 		fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j,
20443f843443Smillert 		    mi[i].mountpoint,
20455fea0b85Smillert 		    fstypesnames[lp->d_partitions[j].p_fstype],
20465fea0b85Smillert 		    j == 0 ? 1 : 2);
2047bd6726faSmillert 	}
2048bd6726faSmillert 	fclose(fp);
2049bd6726faSmillert 	return(0);
2050bd6726faSmillert }
205124a2c1a4Smillert 
205224a2c1a4Smillert int
205324a2c1a4Smillert get_offset(lp, partno)
205424a2c1a4Smillert 	struct disklabel *lp;
205524a2c1a4Smillert 	int partno;
205624a2c1a4Smillert {
205724a2c1a4Smillert 	u_int32_t ui;
205824a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
205924a2c1a4Smillert 
206024a2c1a4Smillert 	for (;;) {
206124a2c1a4Smillert 		ui = getuint(lp, partno, "offset",
206224a2c1a4Smillert 		   "Starting sector for this partition.", pp->p_offset,
206324a2c1a4Smillert 		   pp->p_offset, 0, DO_CONVERSIONS |
206424a2c1a4Smillert 		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
206524a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
206624a2c1a4Smillert 			fputs("Command aborted\n", stderr);
206724a2c1a4Smillert 			return(1);
206824a2c1a4Smillert 		} else if (ui == UINT_MAX)
206924a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
207024a2c1a4Smillert 		else if (ui < starting_sector)
207124a2c1a4Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
207224a2c1a4Smillert 			    " at sector %u, you tried to add a partition at %u."
207324a2c1a4Smillert 			    "  You can use the 'b' command to change the size "
207424a2c1a4Smillert 			    "of the OpenBSD portion.\n" , starting_sector, ui);
207524a2c1a4Smillert 		else if (ui >= ending_sector)
207624a2c1a4Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
207724a2c1a4Smillert 			    "at sector %u, you tried to add a partition at %u."
207824a2c1a4Smillert 			    "  You can use the 'b' command to change the size "
207924a2c1a4Smillert 			    "of the OpenBSD portion.\n", ending_sector, ui);
208049bf537cSderaadt #ifdef AAT0
208149bf537cSderaadt 		else if (partno == 0 && ui != 0)
208249bf537cSderaadt 			fprintf(stderr, "This architecture requires that "
208340f544cdSderaadt 			    "partition 'a' start at sector 0.\n");
208449bf537cSderaadt #endif
208524a2c1a4Smillert 		else
208624a2c1a4Smillert 			break;
208724a2c1a4Smillert 	}
208824a2c1a4Smillert 	pp->p_offset = ui;
208924a2c1a4Smillert 	return(0);
209024a2c1a4Smillert }
209124a2c1a4Smillert 
209224a2c1a4Smillert int
209324a2c1a4Smillert get_size(lp, partno, freep, new)
209424a2c1a4Smillert 	struct disklabel *lp;
209524a2c1a4Smillert 	int partno;
209624a2c1a4Smillert 	u_int32_t *freep;
209724a2c1a4Smillert 	int new;
209824a2c1a4Smillert {
209924a2c1a4Smillert 	u_int32_t ui;
210024a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
210124a2c1a4Smillert 
210224a2c1a4Smillert 	for (;;) {
210324a2c1a4Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
210424a2c1a4Smillert 		    pp->p_size, *freep, pp->p_offset, DO_CONVERSIONS |
210524a2c1a4Smillert 		    ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ?
210624a2c1a4Smillert 		    DO_ROUNDING : 0));
210724a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
210824a2c1a4Smillert 			fputs("Command aborted\n", stderr);
210924a2c1a4Smillert 			return(1);
211024a2c1a4Smillert 		} else if (ui == UINT_MAX) {
211124a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
211224a2c1a4Smillert 			continue;
211324a2c1a4Smillert 		}
211424a2c1a4Smillert 		if (new) {
211524a2c1a4Smillert 			if (ui > *freep)
211624a2c1a4Smillert 				/* XXX - steal space from another partition */
211724a2c1a4Smillert 				fprintf(stderr,"Sorry, there are only %u "
211824a2c1a4Smillert 				    "sectors left\n", *freep);
211924a2c1a4Smillert 			else if (pp->p_offset + ui > ending_sector)
212024a2c1a4Smillert 				fprintf(stderr, "The OpenBSD portion of the "
212124a2c1a4Smillert 				    "disk ends at sector %u, you tried to add "
212224a2c1a4Smillert 				    "a partition ending at sector %u.  You can "
212324a2c1a4Smillert 				    "use the 'b' command to change the size of "
212424a2c1a4Smillert 				    "the OpenBSD portion.\n",
212524a2c1a4Smillert 				    ending_sector, pp->p_offset + ui);
212624a2c1a4Smillert 			else
212724a2c1a4Smillert 				break;			/* ok */
212824a2c1a4Smillert 		} else {
212924a2c1a4Smillert 			if (ui == pp->p_size)
213024a2c1a4Smillert 				break;			/* no change */
21319afbe9eeSmillert 			if (partno == RAW_PART &&
21329afbe9eeSmillert 			    ui + pp->p_offset > lp->d_secperunit) {
213324a2c1a4Smillert 				fputs("'c' partition may not be larger than the disk\n",
213424a2c1a4Smillert 				    stderr);
213524a2c1a4Smillert 			} else if (pp->p_fstype == FS_UNUSED ||
213624a2c1a4Smillert 			    pp->p_fstype == FS_BOOT) {
213724a2c1a4Smillert 				/* don't care what's free */
213824a2c1a4Smillert 				pp->p_size = ui;
213924a2c1a4Smillert 				break;
214024a2c1a4Smillert 			} else {
214124a2c1a4Smillert 				if (ui > pp->p_size + *freep)
214224a2c1a4Smillert 					/* XXX - steal from another partition */
214324a2c1a4Smillert 					fprintf(stderr,
214424a2c1a4Smillert 					    "Size may not be larger than %u "
214524a2c1a4Smillert 					    "sectors\n", pp->p_size + *freep);
214624a2c1a4Smillert 				else {
214724a2c1a4Smillert 					*freep += pp->p_size - ui;
214824a2c1a4Smillert 					pp->p_size = ui;
214924a2c1a4Smillert 					break;			/* ok */
215024a2c1a4Smillert 				}
215124a2c1a4Smillert 			}
215224a2c1a4Smillert 		}
215324a2c1a4Smillert 	}
215424a2c1a4Smillert 	pp->p_size = ui;
215524a2c1a4Smillert 	return(0);
215624a2c1a4Smillert }
215724a2c1a4Smillert 
215824a2c1a4Smillert int
215924a2c1a4Smillert get_fsize(lp, partno)
216024a2c1a4Smillert 	struct disklabel *lp;
216124a2c1a4Smillert 	int partno;
216224a2c1a4Smillert {
216324a2c1a4Smillert 	u_int32_t ui;
216424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
216524a2c1a4Smillert 
216624a2c1a4Smillert 	for (;;) {
216724a2c1a4Smillert 		ui = getuint(lp, partno, "fragment size",
216824a2c1a4Smillert 		    "Size of fs block fragments.  Usually 1024 or 512.",
216924a2c1a4Smillert 		    pp->p_fsize, pp->p_fsize, 0, 0);
217024a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
217124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
217224a2c1a4Smillert 			return(1);
217324a2c1a4Smillert 		} else if (ui == UINT_MAX)
217424a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
217524a2c1a4Smillert 		else
217624a2c1a4Smillert 			break;
217724a2c1a4Smillert 	}
217824a2c1a4Smillert 	if (ui == 0)
217924a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
218024a2c1a4Smillert 	pp->p_fsize = ui;
218124a2c1a4Smillert 	return(0);
218224a2c1a4Smillert }
218324a2c1a4Smillert 
218424a2c1a4Smillert int
218524a2c1a4Smillert get_bsize(lp, partno)
218624a2c1a4Smillert 	struct disklabel *lp;
218724a2c1a4Smillert 	int partno;
218824a2c1a4Smillert {
218924a2c1a4Smillert 	u_int32_t ui;
219024a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
219124a2c1a4Smillert 
219224a2c1a4Smillert 	/* Avoid dividing by zero... */
219324a2c1a4Smillert 	if (pp->p_fsize == 0) {
219424a2c1a4Smillert 		pp->p_frag = 0;
219524a2c1a4Smillert 		return(1);
219624a2c1a4Smillert 	}
219724a2c1a4Smillert 
219824a2c1a4Smillert 	for (;;) {
219924a2c1a4Smillert 		ui = getuint(lp, partno, "block size",
220024a2c1a4Smillert 		    "Size of filesystem blocks.  Usually 8192 or 4096.",
220124a2c1a4Smillert 		    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
220224a2c1a4Smillert 		    0, 0);
220324a2c1a4Smillert 
220424a2c1a4Smillert 		/* sanity checks */
220524a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
220624a2c1a4Smillert 			fputs("Command aborted\n", stderr);
220724a2c1a4Smillert 			return(1);
220824a2c1a4Smillert 		} else if (ui == UINT_MAX)
220924a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
221024a2c1a4Smillert 		else if (ui < getpagesize())
221124a2c1a4Smillert 			fprintf(stderr,
221224a2c1a4Smillert 			    "Error: block size must be at least as big "
221324a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
221424a2c1a4Smillert 		else if (ui % pp->p_fsize != 0)
221524a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
221624a2c1a4Smillert 			    "fragment size.\n", stderr);
221724a2c1a4Smillert 		else if (ui / pp->p_fsize < 1)
221824a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
221924a2c1a4Smillert 			    "fragment size.\n", stderr);
222024a2c1a4Smillert 		else
222124a2c1a4Smillert 			break;
222224a2c1a4Smillert 	}
222324a2c1a4Smillert 	pp->p_frag = ui / pp->p_fsize;
222424a2c1a4Smillert 	return(0);
222524a2c1a4Smillert }
222624a2c1a4Smillert 
222724a2c1a4Smillert int
222824a2c1a4Smillert get_cpg(lp, partno)
222924a2c1a4Smillert 	struct disklabel *lp;
223024a2c1a4Smillert 	int partno;
223124a2c1a4Smillert {
223224a2c1a4Smillert 	u_int32_t ui;
223324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
223424a2c1a4Smillert 
223524a2c1a4Smillert 	for (;;) {
223624a2c1a4Smillert 		ui = getuint(lp, partno, "cpg",
223724a2c1a4Smillert 		    "Number of filesystem cylinders per group."
223824a2c1a4Smillert 		    "  Usually 16 or 8.",
223924a2c1a4Smillert 		    pp->p_cpg ? pp->p_cpg : 16, 16, 0, 0);
224024a2c1a4Smillert 		if (ui == UINT_MAX - 1) {
224124a2c1a4Smillert 			fputs("Command aborted\n", stderr);
224224a2c1a4Smillert 			return(1);
224324a2c1a4Smillert 		} else if (ui == UINT_MAX)
224424a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
224524a2c1a4Smillert 		else
224624a2c1a4Smillert 			break;
224724a2c1a4Smillert 	}
224824a2c1a4Smillert 	pp->p_cpg = ui;
224924a2c1a4Smillert 	return(0);
225024a2c1a4Smillert }
225124a2c1a4Smillert 
225224a2c1a4Smillert int
225324a2c1a4Smillert get_fstype(lp, partno)
225424a2c1a4Smillert 	struct disklabel *lp;
225524a2c1a4Smillert 	int partno;
225624a2c1a4Smillert {
225724a2c1a4Smillert 	char *p;
225824a2c1a4Smillert 	u_int32_t ui;
225924a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
226024a2c1a4Smillert 
226124a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
2262c33fcabaSmillert 		p = getstring("FS type",
226324a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
226424a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
226524a2c1a4Smillert 		if (p == NULL) {
226624a2c1a4Smillert 			fputs("Command aborted\n", stderr);
226724a2c1a4Smillert 			return(1);
226824a2c1a4Smillert 		}
226924a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
227024a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
227124a2c1a4Smillert 				pp->p_fstype = ui;
227224a2c1a4Smillert 				break;
227324a2c1a4Smillert 			}
227424a2c1a4Smillert 		}
227524a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
227624a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
227724a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
227824a2c1a4Smillert 		}
227924a2c1a4Smillert 	} else {
228024a2c1a4Smillert 		for (;;) {
228124a2c1a4Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
228224a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
228324a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
228424a2c1a4Smillert 			if (ui == UINT_MAX - 1) {
228524a2c1a4Smillert 				fputs("Command aborted\n", stderr);
228624a2c1a4Smillert 				return(1);
228724a2c1a4Smillert 			} if (ui == UINT_MAX)
228824a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
228924a2c1a4Smillert 			else
229024a2c1a4Smillert 				break;
229124a2c1a4Smillert 		}
229224a2c1a4Smillert 		pp->p_fstype = ui;
229324a2c1a4Smillert 	}
229424a2c1a4Smillert 	return(0);
229524a2c1a4Smillert }
229624a2c1a4Smillert 
229724a2c1a4Smillert int
229824a2c1a4Smillert get_mp(lp, mp, partno)
229924a2c1a4Smillert 	struct disklabel *lp;
230024a2c1a4Smillert 	char **mp;
230124a2c1a4Smillert 	int partno;
230224a2c1a4Smillert {
230324a2c1a4Smillert 	char *p;
230424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
230524a2c1a4Smillert 
230624a2c1a4Smillert 	if (mp != NULL && pp->p_fstype != FS_UNUSED &&
230724a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
230824a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
2309ddaff619Smillert 		for (;;) {
2310c33fcabaSmillert 			p = getstring("mount point",
231124a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
231224a2c1a4Smillert 			    mp[partno] ? mp[partno] : "none");
231324a2c1a4Smillert 			if (p == NULL) {
231424a2c1a4Smillert 				fputs("Command aborted\n", stderr);
231524a2c1a4Smillert 				return(1);
231624a2c1a4Smillert 			}
2317ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
231824a2c1a4Smillert 				if (mp[partno] != NULL) {
231924a2c1a4Smillert 					free(mp[partno]);
232024a2c1a4Smillert 					mp[partno] = NULL;
232124a2c1a4Smillert 				}
2322ddaff619Smillert 				break;
2323ddaff619Smillert 			}
2324ddaff619Smillert 			if (*p == '/') {
2325ddaff619Smillert 				/* XXX - might as well realloc */
2326ddaff619Smillert 				if (mp[partno] != NULL)
2327ddaff619Smillert 					free(mp[partno]);
232824a2c1a4Smillert 				if ((mp[partno] = strdup(p)) == NULL)
232924a2c1a4Smillert 					errx(4, "out of memory");
2330ddaff619Smillert 				break;
2331ddaff619Smillert 			}
2332ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
233324a2c1a4Smillert 		}
233424a2c1a4Smillert 	}
233524a2c1a4Smillert 	return(0);
233624a2c1a4Smillert }
23373f843443Smillert 
23383f843443Smillert int
23393f843443Smillert micmp(a1, a2)
23403f843443Smillert 	const void *a1;
23413f843443Smillert 	const void *a2;
23423f843443Smillert {
23433f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
23443f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
23453f843443Smillert 
23463f843443Smillert 	/* We want all the NULLs at the end... */
23473f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
23483f843443Smillert 		return(0);
23493f843443Smillert 	else if (mi1->mountpoint == NULL)
23503f843443Smillert 		return(1);
23513f843443Smillert 	else if (mi2->mountpoint == NULL)
23523f843443Smillert 		return(-1);
23533f843443Smillert 	else
23543f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
23553f843443Smillert }
2356c33fcabaSmillert 
2357c33fcabaSmillert void
2358c33fcabaSmillert get_geometry(f, dgpp, bgpp)
2359c33fcabaSmillert 	int f;
2360c33fcabaSmillert 	struct disklabel **dgpp;
2361c33fcabaSmillert 	struct disklabel **bgpp;
2362c33fcabaSmillert {
2363c33fcabaSmillert #ifdef CPU_BIOS
2364c33fcabaSmillert 	int mib[4];
2365c33fcabaSmillert 	size_t size;
2366c33fcabaSmillert 	dev_t devno;
2367c33fcabaSmillert 	bios_diskinfo_t di;
2368c33fcabaSmillert #endif
2369c33fcabaSmillert 	struct stat st;
2370c33fcabaSmillert 	struct disklabel *disk_geop;
2371c33fcabaSmillert 	struct disklabel *bios_geop;
2372c33fcabaSmillert 
2373c33fcabaSmillert 	if (fstat(f, &st) == -1)
2374c33fcabaSmillert 		err(4, "Can't stat device");
2375c33fcabaSmillert 
2376c33fcabaSmillert 	/* Get disk geometry */
2377c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2378c33fcabaSmillert 		errx(4, "out of memory");
2379c33fcabaSmillert 	if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 &&
2380c33fcabaSmillert 	    ioctl(f, DIOCGDINFO, disk_geop) < 0)
2381c33fcabaSmillert 		err(4, "ioctl DIOCGDINFO");
2382c33fcabaSmillert 	*dgpp = disk_geop;
2383c33fcabaSmillert 
2384c33fcabaSmillert 	/* Get BIOS geometry */
2385c33fcabaSmillert 	*bgpp = NULL;
2386c33fcabaSmillert #ifdef CPU_BIOS
2387c33fcabaSmillert 	mib[0] = CTL_MACHDEP;
2388c33fcabaSmillert 	mib[1] = CPU_CHR2BLK;
2389c33fcabaSmillert 	mib[2] = st.st_rdev;
2390c33fcabaSmillert 	size = sizeof(devno);
2391c33fcabaSmillert 	if (sysctl(mib, 3, &devno, &size, NULL, 0) == -1) {
2392c33fcabaSmillert 		warn("sysctl(machdep.chr2blk)");
2393c33fcabaSmillert 		return;
2394c33fcabaSmillert 	}
2395c33fcabaSmillert 	devno = MAKEBOOTDEV(major(devno), 0, 0, DISKUNIT(devno), RAW_PART);
2396c33fcabaSmillert 
2397c33fcabaSmillert 	mib[0] = CTL_MACHDEP;
2398c33fcabaSmillert 	mib[1] = CPU_BIOS;
2399c33fcabaSmillert 	mib[2] = BIOS_DISKINFO;
2400c33fcabaSmillert 	mib[3] = devno;
2401c33fcabaSmillert 	size = sizeof(di);
2402c33fcabaSmillert 	if (sysctl(mib, 4, &di, &size, NULL, 0) == -1) {
2403c33fcabaSmillert 		warn("Can't get bios geometry");
2404c33fcabaSmillert 		return;
2405c33fcabaSmillert 	}
2406c33fcabaSmillert 	if ((bios_geop = calloc(1, sizeof(struct disklabel))) == NULL)
2407c33fcabaSmillert 		errx(4, "out of memory");
2408c33fcabaSmillert 
2409c33fcabaSmillert 	bios_geop->d_secsize = DEV_BSIZE;
2410c33fcabaSmillert 	bios_geop->d_nsectors = di.bios_sectors;
2411c33fcabaSmillert 	bios_geop->d_ntracks = di.bios_heads;
2412c33fcabaSmillert 	bios_geop->d_ncylinders = di.bios_cylinders;
2413c33fcabaSmillert 	bios_geop->d_secpercyl = di.bios_sectors * di.bios_heads;
2414c33fcabaSmillert 	bios_geop->d_secperunit = di.bios_cylinders *
2415c33fcabaSmillert 	    di.bios_heads * di.bios_sectors;
2416c33fcabaSmillert 	*bgpp = bios_geop;
2417c33fcabaSmillert #endif
2418c33fcabaSmillert }
2419c33fcabaSmillert 
2420c33fcabaSmillert void
2421c33fcabaSmillert set_geometry(lp, dgp, bgp, ugp, p)
2422c33fcabaSmillert 	struct disklabel *lp;
2423c33fcabaSmillert 	struct disklabel *dgp;
2424c33fcabaSmillert 	struct disklabel *bgp;
2425c33fcabaSmillert 	struct disklabel *ugp;
2426c33fcabaSmillert 	char *p;
2427c33fcabaSmillert {
2428c33fcabaSmillert 	if (p == NULL) {
2429c33fcabaSmillert 		p = getstring("[d]isk, [b]ios, or [u]ser geometry",
2430c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
2431c33fcabaSmillert 		    "itself thinks it is, 'b' to use what the BIOS says,"
2432c33fcabaSmillert 		    "or 'u' to use the geometry that was found on in the label.",
2433c33fcabaSmillert 		    "d");
2434c33fcabaSmillert 	}
2435c33fcabaSmillert 	if (p == NULL) {
2436c33fcabaSmillert 		fputs("Command aborted\n", stderr);
2437c33fcabaSmillert 		return;
2438c33fcabaSmillert 	}
2439c33fcabaSmillert 	switch (*p) {
2440c33fcabaSmillert 	case 'b':
2441c33fcabaSmillert 	case 'B':
2442c33fcabaSmillert 		if (bgp == NULL)
2443c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2444c33fcabaSmillert 		else {
2445c33fcabaSmillert 			lp->d_secsize = bgp->d_secsize;
2446c33fcabaSmillert 			lp->d_nsectors = bgp->d_nsectors;
2447c33fcabaSmillert 			lp->d_ntracks = bgp->d_ntracks;
2448c33fcabaSmillert 			lp->d_ncylinders = bgp->d_ncylinders;
2449c33fcabaSmillert 			lp->d_secpercyl = bgp->d_secpercyl;
2450c33fcabaSmillert 			lp->d_secperunit = bgp->d_secperunit;
2451c33fcabaSmillert 		}
2452c33fcabaSmillert 		break;
2453c33fcabaSmillert 	case 'd':
2454c33fcabaSmillert 	case 'D':
2455c33fcabaSmillert 		if (dgp == NULL)
2456c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2457c33fcabaSmillert 		else {
2458c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
2459c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
2460c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
2461c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
2462c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
2463c33fcabaSmillert 			lp->d_secperunit = dgp->d_secperunit;
2464c33fcabaSmillert 		}
2465c33fcabaSmillert 		break;
2466c33fcabaSmillert 	case 'u':
2467c33fcabaSmillert 	case 'U':
2468c33fcabaSmillert 		if (ugp == NULL)
2469c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2470c33fcabaSmillert 		else {
2471c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2472c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2473c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2474c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2475c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
2476c33fcabaSmillert 			lp->d_secperunit = ugp->d_secperunit;
2477c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2478c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2479c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2480c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2481c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
2482c33fcabaSmillert 			    ugp->d_secperunit == dgp->d_secperunit)
2483c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2484c33fcabaSmillert 				    "geometry.\n", stderr);
2485c33fcabaSmillert 		}
2486c33fcabaSmillert 		break;
2487c33fcabaSmillert 	default:
2488c33fcabaSmillert 		fputs("You must enter either 'd', 'b', or 'u'.\n", stderr);
2489c33fcabaSmillert 		break;
2490c33fcabaSmillert 	}
2491c33fcabaSmillert }
24929afbe9eeSmillert 
24939afbe9eeSmillert void
24949afbe9eeSmillert zero_partitions(lp, freep)
24959afbe9eeSmillert 	struct disklabel *lp;
24969afbe9eeSmillert 	u_int32_t *freep;
24979afbe9eeSmillert {
24989afbe9eeSmillert 	int i;
24999afbe9eeSmillert 
25009afbe9eeSmillert 	for (i = 0; i < MAXPARTITIONS; i++)
25019afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
25029afbe9eeSmillert 	lp->d_partitions[RAW_PART].p_offset = starting_sector;
25039afbe9eeSmillert 	lp->d_partitions[RAW_PART].p_size = ending_sector - starting_sector;
25049afbe9eeSmillert 	editor_countfree(lp, freep);
25059afbe9eeSmillert }
2506