xref: /openbsd/sbin/disklabel/editor.c (revision 55403f76)
1*55403f76Smillert /*	$OpenBSD: editor.c,v 1.34 1998/04/14 20:02:48 millert Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
46fe57b42Smillert  * Copyright (c) 1997 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.
156fe57b42Smillert  * 3. All advertising materials mentioning features or use of this software
166fe57b42Smillert  *    must display the following acknowledgement:
176fe57b42Smillert  *	This product includes software developed by Todd C. Miller.
186fe57b42Smillert  * 4. The name of the author may not be used to endorse or promote products
196fe57b42Smillert  *    derived from this software without specific prior written permission.
206fe57b42Smillert  *
216fe57b42Smillert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
226fe57b42Smillert  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
236fe57b42Smillert  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
246fe57b42Smillert  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
256fe57b42Smillert  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
266fe57b42Smillert  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
276fe57b42Smillert  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
286fe57b42Smillert  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
296fe57b42Smillert  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
306fe57b42Smillert  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
316fe57b42Smillert  */
326fe57b42Smillert 
336fe57b42Smillert #ifndef lint
34*55403f76Smillert static char rcsid[] = "$OpenBSD: editor.c,v 1.34 1998/04/14 20:02:48 millert Exp $";
356fe57b42Smillert #endif /* not lint */
366fe57b42Smillert 
376fe57b42Smillert #include <sys/types.h>
386fe57b42Smillert #include <sys/param.h>
396fe57b42Smillert #define	DKTYPENAMES
406fe57b42Smillert #include <sys/disklabel.h>
416fe57b42Smillert 
426fe57b42Smillert #include <ufs/ffs/fs.h>
436fe57b42Smillert 
446fe57b42Smillert #include <ctype.h>
456fe57b42Smillert #include <err.h>
466fe57b42Smillert #include <errno.h>
476fe57b42Smillert #include <string.h>
486fe57b42Smillert #include <stdio.h>
496fe57b42Smillert #include <stdlib.h>
506fe57b42Smillert #include <unistd.h>
516fe57b42Smillert 
524793b14cSmillert #include "pathnames.h"
534793b14cSmillert 
546fe57b42Smillert /* flags for getuint() */
556fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
566fe57b42Smillert #define	DO_ROUNDING	0x00000002
576fe57b42Smillert 
58f98aebd4Smillert #ifndef NUMBOOT
59f98aebd4Smillert #define NUMBOOT 0
60f98aebd4Smillert #endif
61f98aebd4Smillert 
6296a888c6Smillert /* structure to describe a portion of a disk */
6396a888c6Smillert struct diskchunk {
6496a888c6Smillert 	u_int32_t start;
6596a888c6Smillert 	u_int32_t stop;
6696a888c6Smillert };
6796a888c6Smillert 
686fe57b42Smillert void	edit_parms __P((struct disklabel *, u_int32_t *));
696fe57b42Smillert int	editor __P((struct disklabel *, int));
706fe57b42Smillert void	editor_add __P((struct disklabel *, u_int32_t *, char *));
716fe57b42Smillert void	editor_modify __P((struct disklabel *, u_int32_t *, char *));
726fe57b42Smillert void	editor_delete __P((struct disklabel *, u_int32_t *, char *));
736fe57b42Smillert void	editor_display __P((struct disklabel *, u_int32_t *, char));
746fe57b42Smillert void	editor_change __P((struct disklabel *, u_int32_t *, char *));
75c0bdc608Smillert void	editor_countfree __P((struct disklabel *, u_int32_t *));
766fe57b42Smillert char	*getstring __P((struct disklabel *, char *, char *, char *));
776fe57b42Smillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int));
786fe57b42Smillert int	has_overlap __P((struct disklabel *, u_int32_t *, int));
796fe57b42Smillert void	make_contiguous __P((struct disklabel *));
8096a888c6Smillert u_int32_t next_offset __P((struct disklabel *, struct partition *));
816fe57b42Smillert int	partition_cmp __P((const void *, const void *));
82a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));
830f820bbbSmillert void	getdisktype __P((struct disklabel *, char *));
8496a888c6Smillert void	find_bounds __P((struct disklabel *));
85e8e8bdb7Sart void	set_bounds __P((struct disklabel *, u_int32_t *));
8696a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *));
8796a888c6Smillert 
8896a888c6Smillert static u_int32_t starting_sector;
8996a888c6Smillert static u_int32_t ending_sector;
906fe57b42Smillert 
916fe57b42Smillert /* from disklabel.c */
926fe57b42Smillert int	checklabel __P((struct disklabel *));
936fe57b42Smillert void	display __P((FILE *, struct disklabel *));
94af98caf3Sderaadt void	display_partition __P((FILE *, struct disklabel *, int, char, int));
95af98caf3Sderaadt int	width_partition __P((struct disklabel *, int));
96af98caf3Sderaadt 
976fe57b42Smillert struct disklabel *readlabel __P((int));
986fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int));
996fe57b42Smillert int	writelabel __P((int, char *, struct disklabel *));
1006fe57b42Smillert extern	char *bootarea, *specname;
10169220492Smillert extern	int donothing;
1024793b14cSmillert #ifdef DOSLABEL
1034793b14cSmillert struct dos_partition *dosdp;	/* DOS partition, if found */
1044793b14cSmillert #endif
1056fe57b42Smillert 
1066fe57b42Smillert /*
1076fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
1086fe57b42Smillert  */
1096fe57b42Smillert int
1106fe57b42Smillert editor(lp, f)
1116fe57b42Smillert 	struct disklabel *lp;
1126fe57b42Smillert 	int f;
1136fe57b42Smillert {
1146fe57b42Smillert 	struct disklabel lastlabel, tmplabel, label = *lp;
11596a888c6Smillert 	struct partition *pp;
11696a888c6Smillert 	u_int32_t freesectors;
1176fe57b42Smillert 	FILE *fp;
1186fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
1196fe57b42Smillert 
12096a888c6Smillert 	/* Don't allow disk type of "unknown" */
12196a888c6Smillert 	getdisktype(&label, "You need to specify a disk type for this disk.");
1226fe57b42Smillert 
12396a888c6Smillert 	/* How big is the OpenBSD portion of the disk?  */
12496a888c6Smillert 	find_bounds(&label);
12596a888c6Smillert 
12696a888c6Smillert 	/* Set freesectors based on bounds and initial label */
127c0bdc608Smillert 	editor_countfree(&label, &freesectors);
12896a888c6Smillert 
12996a888c6Smillert 	/* Make sure there is no partition overlap. */
13096a888c6Smillert 	if (has_overlap(&label, &freesectors, 1))
1316fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1326fe57b42Smillert 
13396a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
13496a888c6Smillert 	pp = &label.d_partitions[2];
13596a888c6Smillert 	if (label.d_npartitions < 3 || pp->p_size == 0) {
13696a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
13796a888c6Smillert 		if (label.d_npartitions < 3)
13896a888c6Smillert 			label.d_npartitions = 3;
13996a888c6Smillert 		pp->p_offset = 0;
14096a888c6Smillert 		pp->p_size = label.d_secperunit;
14196a888c6Smillert 		pp->p_fstype = FS_UNUSED;
14296a888c6Smillert 		pp->p_fsize = pp->p_frag = pp->p_cpg = 0;
14396a888c6Smillert 	}
1440f820bbbSmillert 
1456fe57b42Smillert #ifdef CYLCHECK
1466fe57b42Smillert 	puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically.");
1476fe57b42Smillert #endif
1486fe57b42Smillert 
149f98aebd4Smillert #if defined(OLD_SCSI)
150f98aebd4Smillert 	/* Some ports use the old scsi system that doesn't get the geom right */
151*55403f76Smillert 	if (strcmp(label.d_packname, "fictitious") == 0)
152f98aebd4Smillert 		puts("Warning, driver-generated label.  Disk parameters may be "
153f98aebd4Smillert 		    "incorrect.");
154f98aebd4Smillert #endif
155*55403f76Smillert 	/* Set d_bbsize and d_sbsize as neccesary */
156*55403f76Smillert 	if (strcmp(label.d_packname, "fictitious") == 0) {
157*55403f76Smillert 		if (label.d_bbsize == 0)
158*55403f76Smillert 			label.d_bbsize = BBSIZE;
159*55403f76Smillert 		if (label.d_sbsize == 0)
160*55403f76Smillert 			label.d_sbsize = SBSIZE;
161*55403f76Smillert 	}
162f98aebd4Smillert 
16396a888c6Smillert 	puts("\nInitial label editor (enter '?' for help at any prompt)");
1646fe57b42Smillert 	lastlabel = label;
1656fe57b42Smillert 	for (;;) {
1666fe57b42Smillert 		fputs("> ", stdout);
1676fe57b42Smillert 		fflush(stdout);
1686fe57b42Smillert 		rewind(stdin);
1696e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1706e0becc5Smillert 			putchar('\n');
1716e0becc5Smillert 			buf[0] = 'q';
1726e0becc5Smillert 			buf[1] = '\0';
1736e0becc5Smillert 		}
174260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
175260513deSmillert 			continue;
176260513deSmillert 		arg = strtok(NULL, " \t\r\n");
1776fe57b42Smillert 
1786fe57b42Smillert 		switch (*cmd) {
1796fe57b42Smillert 
1806fe57b42Smillert 		case '?':
181ea37abd3Sderaadt 		case 'h':
182ea37abd3Sderaadt 			puts("Available commands:");
183ea37abd3Sderaadt 			puts("\tp [unit]   - print label.");
1849bb06b6bSderaadt 			puts("\tM          - show entire OpenBSD man page for disklabel.");
1856fe57b42Smillert 			puts("\te          - edit drive parameters.");
1866fe57b42Smillert 			puts("\ta [part]   - add new partition.");
18796a888c6Smillert 			puts("\tb          - set OpenBSD disk boundaries.");
1886fe57b42Smillert 			puts("\tc [part]   - change partition size.");
1896fe57b42Smillert 			puts("\td [part]   - delete partition.");
1906fe57b42Smillert 			puts("\tm [part]   - modify existing partition.");
191c0bdc608Smillert 			puts("\tr          - recalculate free space.");
1926fe57b42Smillert 			puts("\tu          - undo last change.");
1936fe57b42Smillert 			puts("\ts [path]   - save label to file.");
194040947cfSmillert 			puts("\tw          - write label to disk.");
1956fe57b42Smillert 			puts("\tq          - quit and save changes.");
1966fe57b42Smillert 			puts("\tx          - exit without saving changes.");
197ea37abd3Sderaadt 			puts("\t?          - this message.");
19896a888c6Smillert 			puts("Numeric parameters may use suffixes to indicate units:\n\t'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\tNon-sector units will be rounded to the nearest cylinder.");
1996fe57b42Smillert 			break;
2006fe57b42Smillert 
2016fe57b42Smillert 		case 'a':
2026fe57b42Smillert 			tmplabel = lastlabel;
2036fe57b42Smillert 			lastlabel = label;
20496a888c6Smillert 			editor_add(&label, &freesectors, arg);
20596a888c6Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
20696a888c6Smillert 				lastlabel = tmplabel;
20796a888c6Smillert 			break;
20896a888c6Smillert 
20996a888c6Smillert 		case 'b':
21096a888c6Smillert 			tmplabel = lastlabel;
21196a888c6Smillert 			lastlabel = label;
212e8e8bdb7Sart 			set_bounds(&label, &freesectors);
2136fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2146fe57b42Smillert 				lastlabel = tmplabel;
2156fe57b42Smillert 			break;
2166fe57b42Smillert 
2176fe57b42Smillert 		case 'c':
2186fe57b42Smillert 			tmplabel = lastlabel;
2196fe57b42Smillert 			lastlabel = label;
22096a888c6Smillert 			editor_change(&label, &freesectors, arg);
2216fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2226fe57b42Smillert 				lastlabel = tmplabel;
2236fe57b42Smillert 			break;
2246fe57b42Smillert 
2256fe57b42Smillert 		case 'd':
2266fe57b42Smillert 			tmplabel = lastlabel;
2276fe57b42Smillert 			lastlabel = label;
22896a888c6Smillert 			editor_delete(&label, &freesectors, arg);
2296fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2306fe57b42Smillert 				lastlabel = tmplabel;
2316fe57b42Smillert 			break;
2326fe57b42Smillert 
2336fe57b42Smillert 		case 'm':
2346fe57b42Smillert 			tmplabel = lastlabel;
2356fe57b42Smillert 			lastlabel = label;
23696a888c6Smillert 			editor_modify(&label, &freesectors, arg);
2376fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2386fe57b42Smillert 				lastlabel = tmplabel;
2396fe57b42Smillert 			break;
2406fe57b42Smillert 
2416fe57b42Smillert 		case 'p':
24296a888c6Smillert 			editor_display(&label, &freesectors, arg ? *arg : 0);
2436fe57b42Smillert 			break;
2446fe57b42Smillert 
2455d12b01bSderaadt 		case 'M':
2464793b14cSmillert 			fp = popen(_PATH_LESS, "w");
2475d12b01bSderaadt 			if (fp) {
2485d12b01bSderaadt 				extern char manpage[];
2495d12b01bSderaadt 
2505d12b01bSderaadt 				(void) fwrite(manpage, strlen(manpage), 1, fp);
2515d12b01bSderaadt 				pclose(fp);
2525d12b01bSderaadt 			}
2535d12b01bSderaadt 			break;
2545d12b01bSderaadt 
2556fe57b42Smillert 		case 'q':
25669220492Smillert 			if (donothing) {
25769220492Smillert 				puts("In no change mode, not writing label.");
25869220492Smillert 				return(1);
25969220492Smillert 			}
2606fe57b42Smillert 			if (memcmp(lp, &label, sizeof(label)) == 0) {
2616fe57b42Smillert 				puts("No changes.");
2626fe57b42Smillert 				return(1);
2636fe57b42Smillert 			}
2646fe57b42Smillert 			do {
2656fe57b42Smillert 				arg = getstring(lp, "Save changes?",
2666fe57b42Smillert 				    "Save changes you have made to the label?",
2676fe57b42Smillert 				    "n");
26896a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
26996a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
2706fe57b42Smillert 				*lp = label;
2716fe57b42Smillert 				if (writelabel(f, bootarea, lp) == 0)
2726fe57b42Smillert 					return(0);
2736fe57b42Smillert 			}
2746fe57b42Smillert 			return(1);
2756fe57b42Smillert 			/* NOTREACHED */
2766fe57b42Smillert 			break;
2776fe57b42Smillert 
278c0bdc608Smillert 		case 'r':
279c0bdc608Smillert 		    /* Recalculate free space */
280c0bdc608Smillert 		    editor_countfree(&label, &freesectors);
281c0bdc608Smillert 		    puts("Recalculated free space.");
282c0bdc608Smillert 		    break;
283c0bdc608Smillert 
2846fe57b42Smillert 		case 's':
2856fe57b42Smillert 			if (arg == NULL) {
286260513deSmillert 				arg = getstring(lp, "Filename",
2876fe57b42Smillert 				    "Name of the file to save label into.",
2886fe57b42Smillert 				    NULL);
28996a888c6Smillert 				if (arg == NULL && *arg == '\0')
2906fe57b42Smillert 					break;
2916fe57b42Smillert 			}
2926fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
2936fe57b42Smillert 				warn("cannot open %s", arg);
2946fe57b42Smillert 			} else {
2956fe57b42Smillert 				display(fp, &label);
2966fe57b42Smillert 				(void)fclose(fp);
2976fe57b42Smillert 			}
2986fe57b42Smillert 			break;
2996fe57b42Smillert 
3006fe57b42Smillert 		case 'u':
3016fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0) {
3026fe57b42Smillert 				puts("Nothing to undo!");
3036fe57b42Smillert 			} else {
3046fe57b42Smillert 				tmplabel = label;
3056fe57b42Smillert 				label = lastlabel;
3066fe57b42Smillert 				lastlabel = tmplabel;
307c0bdc608Smillert 				/* Recalculate free space */
308c0bdc608Smillert 				editor_countfree(&label, &freesectors);
3096fe57b42Smillert 				puts("Last change undone.");
3106fe57b42Smillert 			}
3116fe57b42Smillert 			break;
3126fe57b42Smillert 
313040947cfSmillert 		case 'w':
314040947cfSmillert 			if (donothing)
315040947cfSmillert 				puts("In no change mode, not writing label.");
316040947cfSmillert 			else if (memcmp(lp, &label, sizeof(label)) == 0)
317040947cfSmillert 				puts("No changes.");
318040947cfSmillert 			else if (writelabel(f, bootarea, &label) != 0)
319040947cfSmillert 				warnx("unable to write label");
3205af08e9cSmillert 			else
3215af08e9cSmillert 				*lp = label;
322040947cfSmillert 			break;
323040947cfSmillert 
3246fe57b42Smillert 		case 'x':
3256fe57b42Smillert 			return(1);
3266fe57b42Smillert 			break;
3276fe57b42Smillert 
3286fe57b42Smillert 		case '\n':
3296fe57b42Smillert 			break;
3306fe57b42Smillert 
3316fe57b42Smillert 		case 'e':
3326fe57b42Smillert 			tmplabel = lastlabel;
3336fe57b42Smillert 			lastlabel = label;
33496a888c6Smillert 			edit_parms(&label, &freesectors);
3356fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
3366fe57b42Smillert 				lastlabel = tmplabel;
3376fe57b42Smillert 			break;
3386fe57b42Smillert 
3396fe57b42Smillert 		default:
3406fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
3416fe57b42Smillert 			break;
3426fe57b42Smillert 		}
3436fe57b42Smillert 	}
3446fe57b42Smillert }
3456fe57b42Smillert 
3466fe57b42Smillert /*
3476fe57b42Smillert  * Add a new partition.
3486fe57b42Smillert  */
3496fe57b42Smillert void
3506fe57b42Smillert editor_add(lp, freep, p)
3516fe57b42Smillert 	struct disklabel *lp;
3526fe57b42Smillert 	u_int32_t *freep;
3536fe57b42Smillert 	char *p;
3546fe57b42Smillert {
35596a888c6Smillert 	struct partition *pp;
35696a888c6Smillert 	struct diskchunk *chunks;
3576fe57b42Smillert 	char buf[BUFSIZ];
3586fe57b42Smillert 	int i, partno;
35996a888c6Smillert 	u_int32_t ui, old_offset, old_size;
3606fe57b42Smillert 
3616fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
3626fe57b42Smillert 	if (*freep == 0) {
3636fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
3646fe57b42Smillert 		    stderr);
3656fe57b42Smillert 		return;
3666fe57b42Smillert 	}
3676fe57b42Smillert 
3686fe57b42Smillert 	/* XXX - make more like other editor_* */
3696fe57b42Smillert 	if (p != NULL) {
3706fe57b42Smillert 		partno = p[0] - 'a';
3716fe57b42Smillert 		if (partno < 0 || partno >= MAXPARTITIONS) {
3726fe57b42Smillert 			fprintf(stderr,
3736fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
3746fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
3756fe57b42Smillert 			return;
37696a888c6Smillert 		} else if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
377f6299b35Sderaadt 		    lp->d_partitions[partno].p_size != 0) {
378f6299b35Sderaadt 			fprintf(stderr,
379f6299b35Sderaadt 			    "Partition '%c' exists.  Delete it first.\n",
380f6299b35Sderaadt 			    p[0]);
381f6299b35Sderaadt 			return;
3826fe57b42Smillert 		}
3836fe57b42Smillert 	} else {
3846fe57b42Smillert 		/* Find first unused partition that is not 'b' or 'c' */
3856fe57b42Smillert 		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {
3866fe57b42Smillert 			if (lp->d_partitions[partno].p_size == 0 &&
3876fe57b42Smillert 			    partno != 1 && partno != 2)
3886fe57b42Smillert 				break;
3896fe57b42Smillert 		}
3906fe57b42Smillert 		if (partno < MAXPARTITIONS) {
3916fe57b42Smillert 			buf[0] = partno + 'a';
3926fe57b42Smillert 			buf[1] = '\0';
3936fe57b42Smillert 			p = &buf[0];
3946fe57b42Smillert 		} else
3956fe57b42Smillert 			p = NULL;
3966fe57b42Smillert 		for (;;) {
3976fe57b42Smillert 			p = getstring(lp, "partition",
3986fe57b42Smillert 			    "The letter of the new partition, a - p.", p);
39996a888c6Smillert 			if (p == NULL)
40096a888c6Smillert 				return;
4016fe57b42Smillert 			partno = p[0] - 'a';
40296a888c6Smillert 			if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
40396a888c6Smillert 			    lp->d_partitions[partno].p_size != 0) {
40496a888c6Smillert 				fprintf(stderr,
40596a888c6Smillert 				    "Partition '%c' already exists.\n", p[0]);
40696a888c6Smillert 			} else if (partno >= 0 && partno < MAXPARTITIONS)
4076fe57b42Smillert 				break;
4086fe57b42Smillert 			fprintf(stderr,
4096fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
4106fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
4116fe57b42Smillert 		}
4126fe57b42Smillert 	}
41396a888c6Smillert 
41496a888c6Smillert 	/* Increase d_npartitions if necesary */
41596a888c6Smillert 	if (partno >= lp->d_npartitions)
41696a888c6Smillert 		lp->d_npartitions = partno + 1;
41796a888c6Smillert 
41896a888c6Smillert 	/* Set defaults */
4196fe57b42Smillert 	pp = &lp->d_partitions[partno];
4206fe57b42Smillert 	if (partno >= lp->d_npartitions)
4216fe57b42Smillert 		lp->d_npartitions = partno + 1;
4226fe57b42Smillert 	memset(pp, 0, sizeof(*pp));
42396a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
4246fe57b42Smillert 	pp->p_fsize = 1024;
4256fe57b42Smillert 	pp->p_frag = 8;
4266fe57b42Smillert 	pp->p_cpg = 16;
42796a888c6Smillert 	pp->p_size = *freep;
42896a888c6Smillert 	pp->p_offset = next_offset(lp, pp);	/* must be computed last */
429f98aebd4Smillert #if NUMBOOT == 1
430f98aebd4Smillert 	/* Don't clobber boot blocks */
431f98aebd4Smillert 	if (pp->p_offset == 0) {
4328dddfaa0Smillert 		pp->p_offset = lp->d_secpercyl;
4338dddfaa0Smillert 		pp->p_size -= lp->d_secpercyl;
434f98aebd4Smillert 	}
435f98aebd4Smillert #endif
43696a888c6Smillert 	old_offset = pp->p_offset;
43796a888c6Smillert 	old_size = pp->p_size;
43896a888c6Smillert 
43996a888c6Smillert getoff1:
44096a888c6Smillert 	/* Get offset */
44196a888c6Smillert 	for (;;) {
44296a888c6Smillert 		ui = getuint(lp, partno, "offset",
44396a888c6Smillert 		   "Starting sector for this partition.", pp->p_offset,
44496a888c6Smillert 		   pp->p_offset, DO_CONVERSIONS |
44596a888c6Smillert 		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
44696a888c6Smillert 		if (ui == UINT_MAX - 1) {
44796a888c6Smillert 			fputs("Command aborted\n", stderr);
44896a888c6Smillert 			pp->p_size = 0;		/* effective delete */
44996a888c6Smillert 			return;
45096a888c6Smillert 		} else if (ui == UINT_MAX)
45196a888c6Smillert 			fputs("Invalid entry\n", stderr);
45296a888c6Smillert 		else if (ui < starting_sector)
45396a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
454f98aebd4Smillert 			    " at sector %u, you tried to add a partition at %u."
455f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
456f98aebd4Smillert 			    "of the OpenBSD portion.\n" , starting_sector, ui);
45796a888c6Smillert 		else if (ui >= ending_sector)
45896a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
459f98aebd4Smillert 			    "at sector %u, you tried to add a partition at %u."
460f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
461f98aebd4Smillert 			    "of the OpenBSD portion.\n", ending_sector, ui);
46296a888c6Smillert 		else
46396a888c6Smillert 			break;
46496a888c6Smillert 	}
46596a888c6Smillert 	pp->p_offset = ui;
46696a888c6Smillert 
46796a888c6Smillert 	/* Recompute recommended size based on new offset */
46896a888c6Smillert 	ui = pp->p_fstype;
46996a888c6Smillert 	pp->p_fstype = FS_UNUSED;
47096a888c6Smillert 	chunks = free_chunks(lp);
47196a888c6Smillert 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
47296a888c6Smillert 		if (pp->p_offset >= chunks[i].start &&
47396a888c6Smillert 		    pp->p_offset < chunks[i].stop) {
47496a888c6Smillert 			pp->p_size = chunks[i].stop - pp->p_offset;
47596a888c6Smillert 			break;
47696a888c6Smillert 		}
47796a888c6Smillert 	}
47896a888c6Smillert 	pp->p_fstype = ui;
47996a888c6Smillert 
48096a888c6Smillert 	/* Get size */
48196a888c6Smillert 	for (;;) {
48296a888c6Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
48396a888c6Smillert 		    pp->p_size, *freep, DO_CONVERSIONS |
48496a888c6Smillert 		    ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ?
48596a888c6Smillert 		    DO_ROUNDING : 0));
48696a888c6Smillert 		if (ui == UINT_MAX - 1) {
48796a888c6Smillert 			fputs("Command aborted\n", stderr);
48896a888c6Smillert 			pp->p_size = 0;		/* effective delete */
48996a888c6Smillert 			return;
49096a888c6Smillert 		} else if (ui == UINT_MAX)
49196a888c6Smillert 			fputs("Invalid entry\n", stderr);
49296a888c6Smillert 		else if (ui > *freep)
49396a888c6Smillert 			/* XXX - prompt user to steal space from another partition */
49496a888c6Smillert 			fprintf(stderr,"Sorry, there are only %u sectors left\n",
49596a888c6Smillert 			    *freep);
49696a888c6Smillert 		else if (pp->p_offset + ui > ending_sector)
49796a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
49896a888c6Smillert 			    "at sector %u, you tried to add a partition ending "
499f98aebd4Smillert 			    "at sector %u.  You can use the 'b' command to "
500f98aebd4Smillert 			    "change the size of the OpenBSD portion.\n",
50196a888c6Smillert 			    ending_sector, pp->p_offset + ui);
50296a888c6Smillert 		else
50396a888c6Smillert 			break;
50496a888c6Smillert 	}
50596a888c6Smillert 	pp->p_size = ui;
50696a888c6Smillert 	if (pp->p_size == 0)
50796a888c6Smillert 		return;
50896a888c6Smillert 
50996a888c6Smillert 	/* Check for overlap */
51096a888c6Smillert 	if (has_overlap(lp, freep, 0)) {
5114793b14cSmillert 		printf("\nPlease re-enter an offset and size for partition "
5124793b14cSmillert 		    "%c.\n", 'a' + partno);
51396a888c6Smillert 		pp->p_offset = old_offset;
51496a888c6Smillert 		pp->p_size = old_size;
51596a888c6Smillert 		goto getoff1;		/* Yeah, I know... */
51696a888c6Smillert 	}
5176fe57b42Smillert 
5186fe57b42Smillert 	/* Get fstype */
5196fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
5206fe57b42Smillert 		p = getstring(lp, "FS type",
5216fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
5226fe57b42Smillert 		    fstypenames[pp->p_fstype]);
52396a888c6Smillert 		if (p == NULL) {
52496a888c6Smillert 			fputs("Command aborted\n", stderr);
52596a888c6Smillert 			pp->p_size = 0;		/* effective delete */
52696a888c6Smillert 			return;
52796a888c6Smillert 		}
5286fe57b42Smillert 		for (i = 0; i < FSMAXTYPES; i++) {
5296fe57b42Smillert 			if (!strcasecmp(p, fstypenames[i])) {
5306fe57b42Smillert 				pp->p_fstype = i;
5316fe57b42Smillert 				break;
5326fe57b42Smillert 			}
5336fe57b42Smillert 		}
5346fe57b42Smillert 		if (i >= FSMAXTYPES) {
5356fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
5366fe57b42Smillert 			pp->p_fstype = FS_OTHER;
5376fe57b42Smillert 		}
5386fe57b42Smillert 	} else {
5396fe57b42Smillert 		for (;;) {
5406fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
5416fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
5426fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
54396a888c6Smillert 			if (ui == UINT_MAX - 1) {
54496a888c6Smillert 				fputs("Command aborted\n", stderr);
54596a888c6Smillert 				pp->p_size = 0;		/* effective delete */
54696a888c6Smillert 				return;
54796a888c6Smillert 			} if (ui == UINT_MAX)
5486fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5496fe57b42Smillert 			else
5506fe57b42Smillert 				break;
5516fe57b42Smillert 		}
5526fe57b42Smillert 		pp->p_fstype = ui;
5536fe57b42Smillert 	}
5546fe57b42Smillert 
5556fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
5566fe57b42Smillert 		/* get fsize */
5576fe57b42Smillert 		for (;;) {
5586fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
5596fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
5606fe57b42Smillert 			    pp->p_fsize, pp->p_fsize, 0);
56196a888c6Smillert 			if (ui == UINT_MAX - 1) {
56296a888c6Smillert 				fputs("Command aborted\n", stderr);
56396a888c6Smillert 				pp->p_size = 0;		/* effective delete */
56496a888c6Smillert 				return;
56596a888c6Smillert 			} else if (ui == UINT_MAX)
5666fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5676fe57b42Smillert 			else
5686fe57b42Smillert 				break;
5696fe57b42Smillert 		}
5706fe57b42Smillert 		pp->p_fsize = ui;
5716fe57b42Smillert 		if (pp->p_fsize == 0)
5726fe57b42Smillert 			puts("Zero fragment size implies zero block size");
5736fe57b42Smillert 
5746fe57b42Smillert 		/* get bsize */
5756fe57b42Smillert 		/* XXX - do before frag size? */
5766fe57b42Smillert 		for (; pp->p_fsize > 0;) {
5776fe57b42Smillert 			ui = getuint(lp, partno, "block size",
5786fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
5796fe57b42Smillert 			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
5806fe57b42Smillert 			    0);
5816fe57b42Smillert 
5826fe57b42Smillert 			/* sanity checks */
58396a888c6Smillert 			if (ui == UINT_MAX - 1) {
58496a888c6Smillert 				fputs("Command aborted\n", stderr);
58596a888c6Smillert 				pp->p_size = 0;		/* effective delete */
58696a888c6Smillert 				return;
58796a888c6Smillert 			} else if (ui == UINT_MAX)
5886fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5896fe57b42Smillert 			else if (ui < getpagesize())
5906fe57b42Smillert 				fprintf(stderr,
5916fe57b42Smillert 				    "Error: block size must be at least as big "
5926fe57b42Smillert 				    "as page size (%d).\n", getpagesize());
5936fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
5946fe57b42Smillert 				fputs("Error: block size must be a multiple of the fragment size.\n", stderr);
5956fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
5966fe57b42Smillert 				fputs("Error: block size must be at least as big as fragment size.\n", stderr);
5976fe57b42Smillert 			else
5986fe57b42Smillert 				break;
5996fe57b42Smillert 		}
6006fe57b42Smillert 		pp->p_frag = ui / pp->p_fsize;
6016fe57b42Smillert 
6026fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
6036fe57b42Smillert 			/* get cpg */
6046fe57b42Smillert 			for (;;) {
6056fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
6066fe57b42Smillert 				    "Number of filesystem cylinders per group.  Usually 16 or 8.",
6076fe57b42Smillert 				    pp->p_cpg, pp->p_cpg, 0);
60896a888c6Smillert 				if (ui == UINT_MAX - 1) {
60996a888c6Smillert 					fputs("Command aborted\n", stderr);
61096a888c6Smillert 					pp->p_size = 0;	/* effective delete */
61196a888c6Smillert 					return;
61296a888c6Smillert 				} else if (ui == UINT_MAX)
6136fe57b42Smillert 					fputs("Invalid entry\n", stderr);
6146fe57b42Smillert 				else
6156fe57b42Smillert 					break;
6166fe57b42Smillert 			}
6176fe57b42Smillert 			pp->p_cpg = ui;
6186fe57b42Smillert 		}
6196fe57b42Smillert 	}
62096a888c6Smillert 	/* Update free sector count and make sure things stay contiguous. */
6216fe57b42Smillert 	*freep -= pp->p_size;
62296a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
62396a888c6Smillert 	    has_overlap(lp, freep, -1))
6246fe57b42Smillert 		make_contiguous(lp);
6256fe57b42Smillert }
6266fe57b42Smillert 
6276fe57b42Smillert /*
6286fe57b42Smillert  * Change an existing partition.
6296fe57b42Smillert  */
6306fe57b42Smillert void
6316fe57b42Smillert editor_modify(lp, freep, p)
6326fe57b42Smillert 	struct disklabel *lp;
6336fe57b42Smillert 	u_int32_t *freep;
6346fe57b42Smillert 	char *p;
6356fe57b42Smillert {
6366fe57b42Smillert 	struct partition origpart, *pp;
6376fe57b42Smillert 	u_int32_t ui;
6386fe57b42Smillert 	int partno;
6396fe57b42Smillert 
6406fe57b42Smillert 	/* Change which partition? */
6416fe57b42Smillert 	if (p == NULL) {
6426fe57b42Smillert 		p = getstring(lp, "partition to modify",
6436fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
6446fe57b42Smillert 	}
64596a888c6Smillert 	if (p == NULL) {
64696a888c6Smillert 		fputs("Command aborted\n", stderr);
64796a888c6Smillert 		return;
64896a888c6Smillert 	}
6496fe57b42Smillert 	partno = p[0] - 'a';
6506fe57b42Smillert 	pp = &lp->d_partitions[partno];
6516fe57b42Smillert 	origpart = lp->d_partitions[partno];
6526fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
6536fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
6546fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
6556fe57b42Smillert 		return;
6566fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
6576fe57b42Smillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
6586fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
6596fe57b42Smillert 		return;
6606fe57b42Smillert 	}
6616fe57b42Smillert 
6626fe57b42Smillert 	/* Get filesystem type */
6636fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
6646fe57b42Smillert 		p = getstring(lp, "FS type",
6656fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
6666fe57b42Smillert 		    fstypenames[pp->p_fstype]);
66796a888c6Smillert 		if (p == NULL) {
66896a888c6Smillert 			fputs("Command aborted\n", stderr);
66996a888c6Smillert 			pp->p_size = 0;		/* effective delete */
67096a888c6Smillert 			return;
67196a888c6Smillert 		}
6726fe57b42Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
6736fe57b42Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
6746fe57b42Smillert 				pp->p_fstype = ui;
6756fe57b42Smillert 				break;
6766fe57b42Smillert 			}
6776fe57b42Smillert 		}
6786fe57b42Smillert 		if (ui >= FSMAXTYPES) {
6796fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
6806fe57b42Smillert 			pp->p_fstype = FS_OTHER;
6816fe57b42Smillert 		}
6826fe57b42Smillert 	} else {
6836fe57b42Smillert 		for (;;) {
6846fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
6856fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
6866fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
68796a888c6Smillert 			if (ui == UINT_MAX - 1) {
68896a888c6Smillert 				fputs("Command aborted\n", stderr);
68996a888c6Smillert 				pp->p_size = 0;		/* effective delete */
69096a888c6Smillert 				return;
69196a888c6Smillert 			} else if (ui == UINT_MAX)
6926fe57b42Smillert 				fputs("Invalid entry\n", stderr);
6936fe57b42Smillert 			else
6946fe57b42Smillert 				break;
6956fe57b42Smillert 		}
6966fe57b42Smillert 		pp->p_fstype = ui;
6976fe57b42Smillert 	}
6986fe57b42Smillert 
6996fe57b42Smillert 	/* Did they disable/enable the partition? */
700229f463eSmillert 	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&
701229f463eSmillert 	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)
7026fe57b42Smillert 		*freep += origpart.p_size;
703229f463eSmillert 	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
704229f463eSmillert 	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {
7056fe57b42Smillert 		if (pp->p_size > *freep) {
7066fe57b42Smillert 			fprintf(stderr,
70796a888c6Smillert 			    "Warning, need %u sectors but there are only %u "
7086fe57b42Smillert 			    "free.  Setting size to %u.\n", pp->p_size, *freep,
7096fe57b42Smillert 			    *freep);
7106fe57b42Smillert 			pp->p_fstype = *freep;
7116fe57b42Smillert 			*freep = 0;
7126fe57b42Smillert 		} else
7136fe57b42Smillert 			*freep -= pp->p_size;		/* have enough space */
7146fe57b42Smillert 	}
7156fe57b42Smillert 
7166fe57b42Smillert getoff2:
7176fe57b42Smillert 	/* Get offset */
7186fe57b42Smillert 	for (;;) {
7196fe57b42Smillert 		ui = getuint(lp, partno, "offset",
7206fe57b42Smillert 		    "Starting sector for this partition.", pp->p_offset,
7216fe57b42Smillert 		    pp->p_offset, DO_CONVERSIONS |
7226fe57b42Smillert 		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
72396a888c6Smillert 		if (ui == UINT_MAX - 1) {
72496a888c6Smillert 			fputs("Command aborted\n", stderr);
72596a888c6Smillert 			*pp = origpart;		/* undo changes */
72696a888c6Smillert 			return;
72796a888c6Smillert 		} else if (ui == UINT_MAX)
7286fe57b42Smillert 			fputs("Invalid entry\n", stderr);
72996a888c6Smillert 		else if (partno != 2 && ui + ui < starting_sector) {
73096a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
731f98aebd4Smillert 			    " at sector %u, you tried to start at %u."
732f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
733f98aebd4Smillert 			    "of the OpenBSD portion.\n", starting_sector, ui);
73496a888c6Smillert 		} else
7356fe57b42Smillert 			break;
7366fe57b42Smillert 	}
7376fe57b42Smillert 	pp->p_offset = ui;
7386fe57b42Smillert 
7396fe57b42Smillert 	/* Get size */
7406fe57b42Smillert 	/* XXX - this loop sucks */
7416fe57b42Smillert 	for (;;) {
7426fe57b42Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
7436fe57b42Smillert 		    pp->p_size, *freep, 1);
7446fe57b42Smillert 
7456fe57b42Smillert 		if (ui == pp->p_size)
7466fe57b42Smillert 			break;			/* no change */
7476fe57b42Smillert 
74896a888c6Smillert 		if (ui == UINT_MAX - 1) {
74996a888c6Smillert 			fputs("Command aborted\n", stderr);
75096a888c6Smillert 			*pp = origpart;		/* undo changes */
75196a888c6Smillert 			return;
75296a888c6Smillert 		} else if (ui == UINT_MAX) {
7536fe57b42Smillert 			fputs("Invalid entry\n", stderr);
7546fe57b42Smillert 			continue;
7556fe57b42Smillert 		} else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) {
7566fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
7576fe57b42Smillert 			    stderr);
7586fe57b42Smillert 			continue;
7596fe57b42Smillert 		}
7606fe57b42Smillert 
761229f463eSmillert 		if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) {
7626fe57b42Smillert 			pp->p_size = ui;	/* don't care what's free */
7636fe57b42Smillert 			break;
7646fe57b42Smillert 		} else {
7656fe57b42Smillert 			if (ui > pp->p_size + *freep)
7666fe57b42Smillert 				/* XXX - prompt user to steal space from another partition */
7676fe57b42Smillert 				fprintf(stderr,
76896a888c6Smillert 				    "Size may not be larger than %u sectors\n",
7696fe57b42Smillert 				    pp->p_size + *freep);
7706fe57b42Smillert 			else {
7716fe57b42Smillert 				*freep += pp->p_size - ui;
7726fe57b42Smillert 				pp->p_size = ui;
7736fe57b42Smillert 				break;
7746fe57b42Smillert 			}
7756fe57b42Smillert 		}
7766fe57b42Smillert 	}
777f98aebd4Smillert 	/* XXX - if (ui % lp->d_secpercyl == 0) make ui + offset on cyl bound */
778f98aebd4Smillert 	pp->p_size = ui;
7796fe57b42Smillert 	if (pp->p_size == 0)
7806fe57b42Smillert 		return;
7816fe57b42Smillert 
7826fe57b42Smillert 	/* Check for overlap and restore if not resolved */
7836fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
7846fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
7856fe57b42Smillert 		pp->p_offset = origpart.p_offset;
7866fe57b42Smillert 		pp->p_size = origpart.p_size;
7876fe57b42Smillert 		goto getoff2;		/* Yeah, I know... */
7886fe57b42Smillert 	}
7896fe57b42Smillert 
7906fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
7916fe57b42Smillert 		/* get fsize */
7926fe57b42Smillert 		for (;;) {
7936fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
7946fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
7956fe57b42Smillert 			    pp->p_fsize, 1024, 0);
79696a888c6Smillert 			if (ui == UINT_MAX - 1) {
79796a888c6Smillert 				fputs("Command aborted\n", stderr);
79896a888c6Smillert 				*pp = origpart;		/* undo changes */
79996a888c6Smillert 				return;
80096a888c6Smillert 			} else if (ui == UINT_MAX)
8016fe57b42Smillert 				fputs("Invalid entry\n", stderr);
8026fe57b42Smillert 			else
8036fe57b42Smillert 				break;
8046fe57b42Smillert 		}
8056fe57b42Smillert 		pp->p_fsize = ui;
8066fe57b42Smillert 		if (pp->p_fsize == 0)
8076fe57b42Smillert 			puts("Zero fragment size implies zero block size");
8086fe57b42Smillert 
8096fe57b42Smillert 		/* get bsize */
8106fe57b42Smillert 		for (; pp->p_fsize > 0;) {
8116fe57b42Smillert 			ui = getuint(lp, partno, "block size",
8126fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
8136fe57b42Smillert 			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
8146fe57b42Smillert 			    0);
8156fe57b42Smillert 
8166fe57b42Smillert 			/* sanity check */
81796a888c6Smillert 			if (ui == UINT_MAX - 1) {
81896a888c6Smillert 				fputs("Command aborted\n", stderr);
81996a888c6Smillert 				*pp = origpart;		/* undo changes */
82096a888c6Smillert 				return;
82196a888c6Smillert 			} else if (ui == UINT_MAX)
8226fe57b42Smillert 				fputs("Invalid entry\n", stderr);
8236fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
8246fe57b42Smillert 				puts("Error: block size must be a multiple of the fragment size.");
8256fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
8266fe57b42Smillert 				puts("Error: block size must be at least as big as fragment size.");
8276fe57b42Smillert 			else {
8286fe57b42Smillert 				pp->p_frag = ui / pp->p_fsize;
8296fe57b42Smillert 				break;
8306fe57b42Smillert 			}
8316fe57b42Smillert 		}
8326fe57b42Smillert 
8336fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
8346fe57b42Smillert 			/* get cpg */
8356fe57b42Smillert 			for (;;) {
8366fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
8376fe57b42Smillert 				    "Number of filesystem cylinders per group."
8386fe57b42Smillert 				    "  Usually 16 or 8.", pp->p_cpg, pp->p_cpg,
8396fe57b42Smillert 				    0);
84096a888c6Smillert 				if (ui == UINT_MAX - 1) {
84196a888c6Smillert 					fputs("Command aborted\n", stderr);
84296a888c6Smillert 					*pp = origpart;	/* undo changes */
84396a888c6Smillert 					return;
84496a888c6Smillert 				} else if (ui == UINT_MAX)
8456fe57b42Smillert 					fputs("Invalid entry\n", stderr);
8466fe57b42Smillert 				else
8476fe57b42Smillert 					break;
8486fe57b42Smillert 			}
8496fe57b42Smillert 			pp->p_cpg = ui;
8506fe57b42Smillert 		}
8516fe57b42Smillert 	}
8526fe57b42Smillert 
8536fe57b42Smillert 	/* Make sure things stay contiguous. */
85496a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
85596a888c6Smillert 	    has_overlap(lp, freep, -1))
8566fe57b42Smillert 		make_contiguous(lp);
8576fe57b42Smillert }
8586fe57b42Smillert 
8596fe57b42Smillert /*
8606fe57b42Smillert  * Delete an existing partition.
8616fe57b42Smillert  */
8626fe57b42Smillert void
8636fe57b42Smillert editor_delete(lp, freep, p)
8646fe57b42Smillert 	struct disklabel *lp;
8656fe57b42Smillert 	u_int32_t *freep;
8666fe57b42Smillert 	char *p;
8676fe57b42Smillert {
8686fe57b42Smillert 	int c;
8696fe57b42Smillert 
8706fe57b42Smillert 	if (p == NULL) {
8716fe57b42Smillert 		p = getstring(lp, "partition to delete",
8726fe57b42Smillert 		    "The letter of the partition to delete, a - p.", NULL);
8736fe57b42Smillert 	}
87496a888c6Smillert 	if (p == NULL) {
87596a888c6Smillert 		fputs("Command aborted\n", stderr);
87696a888c6Smillert 		return;
87796a888c6Smillert 	}
8786fe57b42Smillert 	c = p[0] - 'a';
8796fe57b42Smillert 	if (c < 0 || c >= lp->d_npartitions)
8806fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
8816fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
8826fe57b42Smillert 	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==
8836fe57b42Smillert 	    FS_UNUSED && lp->d_partitions[c].p_size == 0))
8846fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);
8856fe57b42Smillert 	else if (c == 2)
8866fe57b42Smillert 		fputs("You may not delete the 'c' partition.\n", stderr);
88796a888c6Smillert 	else if (lp->d_partitions[c].p_offset >= ending_sector ||
88896a888c6Smillert 	    lp->d_partitions[c].p_offset < starting_sector)
88996a888c6Smillert 		fprintf(stderr, "The OpenBSD portion of the disk ends at sector"
89096a888c6Smillert 		    " %u.\nYou can't remove a partition outside the OpenBSD "
891f98aebd4Smillert 		    "part of the disk.  You can use the 'b' command to change "
892f98aebd4Smillert 		    "the size of the OpenBSD portion.\n", ending_sector);
8936fe57b42Smillert 	else {
89496a888c6Smillert 		/* Update free sector count. */
8956fe57b42Smillert 		if (lp->d_partitions[c].p_fstype != FS_UNUSED &&
896229f463eSmillert 		    lp->d_partitions[c].p_fstype != FS_BOOT &&
8976fe57b42Smillert 		    lp->d_partitions[c].p_size != 0)
8986fe57b42Smillert 			*freep += lp->d_partitions[c].p_size;
8996fe57b42Smillert 
9006fe57b42Smillert 		/* Really delete it (as opposed to just setting to "unused") */
9016fe57b42Smillert 		(void)memset(&lp->d_partitions[c], 0,
9026fe57b42Smillert 		    sizeof(lp->d_partitions[c]));
9036fe57b42Smillert 	}
9046fe57b42Smillert }
9056fe57b42Smillert 
9066fe57b42Smillert /*
9076fe57b42Smillert  * Simplified display() for use with the builtin editor.
9086fe57b42Smillert  */
9096fe57b42Smillert void
9106fe57b42Smillert editor_display(lp, freep, unit)
9116fe57b42Smillert 	struct disklabel *lp;
9126fe57b42Smillert 	u_int32_t *freep;
9136fe57b42Smillert 	char unit;
9146fe57b42Smillert {
9156fe57b42Smillert 	int i;
916af98caf3Sderaadt 	int width;
9176fe57b42Smillert 
9186fe57b42Smillert 	printf("device: %s\n", specname);
9190f820bbbSmillert 	printf("type: %s\n", dktypenames[lp->d_type]);
9206fe57b42Smillert 	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
9216fe57b42Smillert 	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
9226fe57b42Smillert 	printf("bytes/sector: %ld\n", (long)lp->d_secsize);
9236fe57b42Smillert 	printf("sectors/track: %ld\n", (long)lp->d_nsectors);
9246fe57b42Smillert 	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);
9256fe57b42Smillert 	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);
9266fe57b42Smillert 	printf("cylinders: %ld\n", (long)lp->d_ncylinders);
9276fe57b42Smillert 	printf("total sectors: %ld\n", (long)lp->d_secperunit);
9286fe57b42Smillert 	printf("free sectors: %u\n", *freep);
9296fe57b42Smillert 	printf("rpm: %ld\n", (long)lp->d_rpm);
9306fe57b42Smillert 	printf("\n%d partitions:\n", lp->d_npartitions);
931af98caf3Sderaadt 	width = width_partition(lp, unit);
932af98caf3Sderaadt 	printf("#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n",
933af98caf3Sderaadt 		width, width, "size", width, width, "offset");
9346fe57b42Smillert 	for (i = 0; i < lp->d_npartitions; i++)
935af98caf3Sderaadt 		display_partition(stdout, lp, i, unit, width);
9366fe57b42Smillert }
9376fe57b42Smillert 
9386fe57b42Smillert /*
9396fe57b42Smillert  * Find the next reasonable starting offset and returns it.
94096a888c6Smillert  * Assumes there is a least one free sector left (returns 0 if not).
9416fe57b42Smillert  */
9426fe57b42Smillert u_int32_t
94396a888c6Smillert next_offset(lp, pp)
9446fe57b42Smillert 	struct disklabel *lp;
94596a888c6Smillert 	struct partition *pp;
9466fe57b42Smillert {
947f0b4d0a9Smillert 	struct partition **spp;
94896a888c6Smillert 	struct diskchunk *chunks;
949f0b4d0a9Smillert 	u_int16_t npartitions;
95096a888c6Smillert 	u_int32_t new_offset, new_size;
95196a888c6Smillert 	int i, good_offset;
9526fe57b42Smillert 
953a7e61405Smillert 	/* Get a sorted list of the partitions */
95496a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
95596a888c6Smillert 		return(0);
956f0b4d0a9Smillert 
95796a888c6Smillert 	new_offset = starting_sector;
958f0b4d0a9Smillert 	for (i = 0; i < npartitions; i++ ) {
95996a888c6Smillert 		/* Skip the partition for which we are finding an offset */
96096a888c6Smillert 		if (pp == spp[i])
96196a888c6Smillert 			continue;
96296a888c6Smillert 
9636fe57b42Smillert 		/*
9646fe57b42Smillert 		 * Is new_offset inside this partition?  If so,
96596a888c6Smillert 		 * make it the next sector after the partition ends.
9666fe57b42Smillert 		 */
9674793b14cSmillert 		if (spp[i]->p_offset + spp[i]->p_size < ending_sector &&
9684793b14cSmillert 		    ((new_offset >= spp[i]->p_offset &&
96996a888c6Smillert 		    new_offset < spp[i]->p_offset + spp[i]->p_size) ||
97096a888c6Smillert 		    (new_offset + pp->p_size >= spp[i]->p_offset && new_offset
9714793b14cSmillert 		    + pp->p_size <= spp[i]->p_offset + spp[i]->p_size)))
972f0b4d0a9Smillert 			new_offset = spp[i]->p_offset + spp[i]->p_size;
9736fe57b42Smillert 	}
9746fe57b42Smillert 
97596a888c6Smillert 	/* Did we find a suitable offset? */
97696a888c6Smillert 	for (good_offset = 1, i = 0; i < npartitions; i++ ) {
97796a888c6Smillert 		if (new_offset + pp->p_size >= spp[i]->p_offset &&
97896a888c6Smillert 		    new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) {
97996a888c6Smillert 			/* Nope */
98096a888c6Smillert 			good_offset = 0;
98196a888c6Smillert 			break;
98296a888c6Smillert 		}
98396a888c6Smillert 	}
98496a888c6Smillert 
98596a888c6Smillert 	/* Specified size is too big, find something that fits */
98696a888c6Smillert 	if (!good_offset) {
98796a888c6Smillert 		chunks = free_chunks(lp);
98896a888c6Smillert 		new_size = 0;
98996a888c6Smillert 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
99096a888c6Smillert 			if (chunks[i].stop - chunks[i].start > new_size) {
99196a888c6Smillert 			    new_size = chunks[i].stop - chunks[i].start;
99296a888c6Smillert 			    new_offset = chunks[i].start;
99396a888c6Smillert 			}
99496a888c6Smillert 		}
9954793b14cSmillert 		/* XXX - should do something intelligent if new_size == 0 */
99696a888c6Smillert 		pp->p_size = new_size;
99796a888c6Smillert 	}
99896a888c6Smillert 
999f0b4d0a9Smillert 	(void)free(spp);
10006fe57b42Smillert 	return(new_offset);
10016fe57b42Smillert }
10026fe57b42Smillert 
10036fe57b42Smillert /*
10046fe57b42Smillert  * Change the size of an existing partition.
10056fe57b42Smillert  */
10066fe57b42Smillert void
10076fe57b42Smillert editor_change(lp, freep, p)
10086fe57b42Smillert 	struct disklabel *lp;
10096fe57b42Smillert 	u_int32_t *freep;
10106fe57b42Smillert 	char *p;
10116fe57b42Smillert {
10126fe57b42Smillert 	int partno;
10136fe57b42Smillert 	u_int32_t newsize;
10146fe57b42Smillert 
10156fe57b42Smillert 	if (p == NULL) {
10166fe57b42Smillert 		p = getstring(lp, "partition to change size",
10176fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
10186fe57b42Smillert 	}
101996a888c6Smillert 	if (p == NULL) {
102096a888c6Smillert 		fputs("Command aborted\n", stderr);
102196a888c6Smillert 		return;
102296a888c6Smillert 	}
10236fe57b42Smillert 	partno = p[0] - 'a';
10246fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
10256fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
10266fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
10276fe57b42Smillert 		return;
10286fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
1029229f463eSmillert 	    lp->d_partitions[partno].p_size == 0) {
10306fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
10316fe57b42Smillert 		return;
10326fe57b42Smillert 	}
10336fe57b42Smillert 
10346fe57b42Smillert 	printf("Partition %c is currently %u sectors in size (%u free).\n",
10356fe57b42Smillert 	    partno + 'a', lp->d_partitions[partno].p_size, *freep);
1036229f463eSmillert 	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */
10376fe57b42Smillert 	newsize = getuint(lp, partno, "new size", "Size of the partition.  "
10386fe57b42Smillert 	    "You may also say +/- amount for a relative change.",
10396fe57b42Smillert 	    lp->d_partitions[partno].p_size,
10406fe57b42Smillert 	    lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS |
10416fe57b42Smillert 	    (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
104296a888c6Smillert 	if (newsize == UINT_MAX - 1) {
104396a888c6Smillert 		fputs("Command aborted\n", stderr);
104496a888c6Smillert 		return;
104596a888c6Smillert 	} else if (newsize == UINT_MAX) {
10466fe57b42Smillert 		fputs("Invalid entry\n", stderr);
10476fe57b42Smillert 		return;
10486fe57b42Smillert 	} else if (newsize == lp->d_partitions[partno].p_size)
10496fe57b42Smillert 		return;
10506fe57b42Smillert 
1051229f463eSmillert 	if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
1052229f463eSmillert 	    lp->d_partitions[partno].p_fstype != FS_BOOT) {
10536fe57b42Smillert 		if (newsize > lp->d_partitions[partno].p_size) {
10546fe57b42Smillert 			if (newsize - lp->d_partitions[partno].p_size > *freep) {
10556fe57b42Smillert 				fprintf(stderr,
10566fe57b42Smillert 				    "Only %u sectors free, you asked for %u\n",
10576fe57b42Smillert 				    *freep,
10586fe57b42Smillert 				    newsize - lp->d_partitions[partno].p_size);
10596fe57b42Smillert 				return;
10606fe57b42Smillert 			}
10616fe57b42Smillert 			*freep -= newsize - lp->d_partitions[partno].p_size;
10626fe57b42Smillert 		} else if (newsize < lp->d_partitions[partno].p_size) {
10636fe57b42Smillert 			*freep += lp->d_partitions[partno].p_size - newsize;
10646fe57b42Smillert 		}
10656fe57b42Smillert 	} else {
106696a888c6Smillert 		if (partno == 2 && newsize +
10676fe57b42Smillert 		    lp->d_partitions[partno].p_offset > lp->d_secperunit) {
10686fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
10696fe57b42Smillert 			    stderr);
10706fe57b42Smillert 			return;
10716fe57b42Smillert 		}
10726fe57b42Smillert 	}
10736fe57b42Smillert 	lp->d_partitions[partno].p_size = newsize;
107496a888c6Smillert 	if (newsize + lp->d_partitions[partno].p_offset > ending_sector ||
107596a888c6Smillert 	    has_overlap(lp, freep, -1))
10766fe57b42Smillert 		make_contiguous(lp);
10776fe57b42Smillert }
10786fe57b42Smillert 
10796fe57b42Smillert void
10806fe57b42Smillert make_contiguous(lp)
10816fe57b42Smillert 	struct disklabel *lp;
10826fe57b42Smillert {
10836fe57b42Smillert 	struct partition **spp;
10846fe57b42Smillert 	u_int16_t npartitions;
10856fe57b42Smillert 	int i;
10866fe57b42Smillert 
1087a7e61405Smillert 	/* Get a sorted list of the partitions */
108896a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
108996a888c6Smillert 		return;
10906fe57b42Smillert 
10916fe57b42Smillert 	/*
1092a7e61405Smillert 	 * Make everything contiguous but don't muck with start of the first one
109396a888c6Smillert 	 * or partitions not in the BSD part of the label.
10946fe57b42Smillert 	 */
109596a888c6Smillert 	for (i = 1; i < npartitions; i++) {
109696a888c6Smillert 		if (spp[i]->p_offset >= starting_sector ||
109796a888c6Smillert 		    spp[i]->p_offset < ending_sector)
109896a888c6Smillert 			spp[i]->p_offset =
109996a888c6Smillert 			    spp[i - 1]->p_offset + spp[i - 1]->p_size;
110096a888c6Smillert 	}
1101f0b4d0a9Smillert 
1102f0b4d0a9Smillert 	(void)free(spp);
11036fe57b42Smillert }
11046fe57b42Smillert 
11056fe57b42Smillert /*
11066fe57b42Smillert  * Sort the partitions based on starting offset.
11076fe57b42Smillert  * This assumes there can be no overlap.
11086fe57b42Smillert  */
11096fe57b42Smillert int
11106fe57b42Smillert partition_cmp(e1, e2)
11116fe57b42Smillert 	const void *e1, *e2;
11126fe57b42Smillert {
11136fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
11146fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
11156fe57b42Smillert 
11166fe57b42Smillert 	return((int)(p1->p_offset - p2->p_offset));
11176fe57b42Smillert }
11186fe57b42Smillert 
11196fe57b42Smillert char *
11206fe57b42Smillert getstring(lp, prompt, helpstring, oval)
11216fe57b42Smillert 	struct disklabel *lp;
11226fe57b42Smillert 	char *prompt;
11236fe57b42Smillert 	char *helpstring;
11246fe57b42Smillert 	char *oval;
11256fe57b42Smillert {
11266fe57b42Smillert 	static char buf[BUFSIZ];
11276fe57b42Smillert 	int n;
11286fe57b42Smillert 
11296fe57b42Smillert 	buf[0] = '\0';
11306fe57b42Smillert 	do {
11316fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
11326fe57b42Smillert 		fflush(stdout);
11336fe57b42Smillert 		rewind(stdin);
11346e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1135260513deSmillert 			buf[0] = '\0';
113696a888c6Smillert 			if (feof(stdin)) {
113796a888c6Smillert 				putchar('\n');
113896a888c6Smillert 				return(NULL);
113996a888c6Smillert 			}
11406e0becc5Smillert 		}
11416fe57b42Smillert 		n = strlen(buf);
11426fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11436fe57b42Smillert 			buf[--n] = '\0';
11446fe57b42Smillert 		if (buf[0] == '?')
11456fe57b42Smillert 			puts(helpstring);
11466fe57b42Smillert 		else if (oval != NULL && buf[0] == '\0') {
11476fe57b42Smillert 			(void)strncpy(buf, oval, sizeof(buf) - 1);
11486fe57b42Smillert 			buf[sizeof(buf) - 1] = '\0';
11496fe57b42Smillert 		}
11506fe57b42Smillert 	} while (buf[0] == '?');
11516fe57b42Smillert 
11526fe57b42Smillert 	return(&buf[0]);
11536fe57b42Smillert }
11546fe57b42Smillert 
11556fe57b42Smillert /*
11566fe57b42Smillert  * Returns UINT_MAX on error
11576fe57b42Smillert  * XXX - there are way too many parameters here.  Use inline helper functions
11586fe57b42Smillert  */
11596fe57b42Smillert u_int32_t
11606fe57b42Smillert getuint(lp, partno, prompt, helpstring, oval, maxval, flags)
11616fe57b42Smillert 	struct disklabel *lp;
11626fe57b42Smillert 	int partno;
11636fe57b42Smillert 	char *prompt;
11646fe57b42Smillert 	char *helpstring;
11656fe57b42Smillert 	u_int32_t oval;
11666fe57b42Smillert 	u_int32_t maxval;		/* XXX - used inconsistently */
11676fe57b42Smillert 	int flags;
11686fe57b42Smillert {
11696fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
11706fe57b42Smillert 	u_int32_t rval = oval;
11716fe57b42Smillert 	size_t n;
11726fe57b42Smillert 	int mult = 1;
117396a888c6Smillert 	double d;
11746fe57b42Smillert 
11756fe57b42Smillert 	buf[0] = '\0';
11766fe57b42Smillert 	do {
11776fe57b42Smillert 		printf("%s: [%u] ", prompt, oval);
11786fe57b42Smillert 		fflush(stdout);
11796fe57b42Smillert 		rewind(stdin);
11806e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11816e0becc5Smillert 			buf[0] = '\0';
118296a888c6Smillert 			if (feof(stdin)) {
118396a888c6Smillert 				putchar('\n');
118496a888c6Smillert 				return(UINT_MAX - 1);
118596a888c6Smillert 			}
11866e0becc5Smillert 		}
11876fe57b42Smillert 		n = strlen(buf);
11886fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11896fe57b42Smillert 			buf[--n] = '\0';
11906fe57b42Smillert 		if (buf[0] == '?')
11916fe57b42Smillert 			puts(helpstring);
11926fe57b42Smillert 	} while (buf[0] == '?');
11936fe57b42Smillert 
11946fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11956fe57b42Smillert 		rval = maxval;
11966fe57b42Smillert 	} else {
11976fe57b42Smillert 		/* deal with units */
11986fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11996fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
120096a888c6Smillert 				switch (tolower(buf[n-1])) {
12016fe57b42Smillert 
12026fe57b42Smillert 				case 'c':
12036fe57b42Smillert 					mult = lp->d_secpercyl;
12046fe57b42Smillert 					buf[--n] = '\0';
12056fe57b42Smillert 					break;
12066fe57b42Smillert 				case 'b':
12076fe57b42Smillert 					mult = -lp->d_secsize;
12086fe57b42Smillert 					buf[--n] = '\0';
12096fe57b42Smillert 					break;
12106fe57b42Smillert 				case 'k':
12116fe57b42Smillert 					mult = 1024 / lp->d_secsize;
12126fe57b42Smillert 					buf[--n] = '\0';
12136fe57b42Smillert 					break;
12146fe57b42Smillert 				case 'm':
12156fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
12166fe57b42Smillert 					buf[--n] = '\0';
12176fe57b42Smillert 					break;
12181a51a1eeSmillert 				case 'g':
12191a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
12201a51a1eeSmillert 					buf[--n] = '\0';
12211a51a1eeSmillert 					break;
12226fe57b42Smillert 				}
122396a888c6Smillert 			}
12246fe57b42Smillert 
12256fe57b42Smillert 			/* Did they give us an operator? */
12266fe57b42Smillert 			p = &buf[0];
12276fe57b42Smillert 			if (*p == '+' || *p == '-')
12286fe57b42Smillert 				operator = *p++;
12296fe57b42Smillert 
12306fe57b42Smillert 			endptr = p;
123196a888c6Smillert 			errno = 0;
123296a888c6Smillert 			d = strtod(p, &endptr);
123396a888c6Smillert 			if (errno == ERANGE)
123496a888c6Smillert 				rval = UINT_MAX;	/* too big/small */
123596a888c6Smillert 			else if (*endptr != '\0') {
12366fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
12376fe57b42Smillert 				rval = UINT_MAX;
12386fe57b42Smillert 			} else {
123996a888c6Smillert 				/* XXX - should check for overflow */
124096a888c6Smillert 				if (mult > 0)
124196a888c6Smillert 					rval = d * mult;
124296a888c6Smillert 				else
124396a888c6Smillert 					/* Negative mult means divide (fancy) */
124496a888c6Smillert 					rval = d / (-mult);
12456fe57b42Smillert 
124696a888c6Smillert 				/* Apply the operator */
12476fe57b42Smillert 				if (operator == '+')
12486fe57b42Smillert 					rval += oval;
12496fe57b42Smillert 				else if (operator == '-')
12506fe57b42Smillert 					rval = oval - rval;
12516fe57b42Smillert 			}
12526fe57b42Smillert 		}
12536fe57b42Smillert 	}
12546fe57b42Smillert 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
12556fe57b42Smillert 		u_int32_t cyls;
1256260513deSmillert 		/* XXX - should use maxsize and round down if too big */
12576fe57b42Smillert #ifdef CYLCHECK
12586fe57b42Smillert 		/* Always round to nearest cylinder, regardless of units */
12596fe57b42Smillert 		cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5);
12606fe57b42Smillert 		if (rval != cyls * lp->d_secpercyl) {
12616fe57b42Smillert 			rval = cyls * lp->d_secpercyl;
12626fe57b42Smillert 			printf("Rounding to nearest cylinder: %u\n", rval);
12636fe57b42Smillert 		}
12646fe57b42Smillert #else
126596a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
126696a888c6Smillert 		if (mult != 1) {
12676fe57b42Smillert 			cyls = (u_int32_t)((rval / (double)lp->d_secpercyl)
12686fe57b42Smillert 			    + 0.5);
12696fe57b42Smillert 			if (rval != cyls * lp->d_secpercyl) {
12706fe57b42Smillert 				rval = cyls * lp->d_secpercyl;
12716fe57b42Smillert 				printf("Rounding to nearest cylinder: %u\n",
12726fe57b42Smillert 				    rval);
12736fe57b42Smillert 			}
12746fe57b42Smillert 		}
12756fe57b42Smillert #endif
12766fe57b42Smillert 	}
12776fe57b42Smillert 
12786fe57b42Smillert 	return(rval);
12796fe57b42Smillert }
12806fe57b42Smillert 
12816fe57b42Smillert /*
12826fe57b42Smillert  * Check for partition overlap in lp and prompt the user
12836fe57b42Smillert  * to resolve the overlap if any is found.  Returns 1
12846fe57b42Smillert  * if unable to resolve, else 0.
12856fe57b42Smillert  */
12866fe57b42Smillert int
12876fe57b42Smillert has_overlap(lp, freep, resolve)
12886fe57b42Smillert 	struct disklabel *lp;
12896fe57b42Smillert 	u_int32_t *freep;
12906fe57b42Smillert 	int resolve;
12916fe57b42Smillert {
12926fe57b42Smillert 	struct partition **spp;
12936fe57b42Smillert 	u_int16_t npartitions;
1294e6aa8bafSmillert 	int c, i, j;
1295e6aa8bafSmillert 	char buf[BUFSIZ];
12966fe57b42Smillert 
1297a7e61405Smillert 	/* Get a sorted list of the partitions */
1298a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
12996fe57b42Smillert 
1300a7e61405Smillert 	if (npartitions < 2) {
1301a7e61405Smillert 		(void)free(spp);
13026fe57b42Smillert 		return(0);			/* nothing to do */
13036fe57b42Smillert 	}
13046fe57b42Smillert 
13056fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
13066fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
13076fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
13086fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
13096fe57b42Smillert 			if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) {
131096a888c6Smillert 				/* Don't print, just return */
131196a888c6Smillert 				if (resolve == -1) {
131296a888c6Smillert 					(void)free(spp);
131396a888c6Smillert 					return(1);
131496a888c6Smillert 				}
131596a888c6Smillert 
13166fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
13176fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
13186fe57b42Smillert 				    / sizeof(**spp);
13196fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
13206fe57b42Smillert 				    / sizeof(**spp);
13216fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
13226fe57b42Smillert 				    'a' + i, 'a' + j);
13236fe57b42Smillert 				puts("         size   offset    fstype   [fsize bsize   cpg]");
1324af98caf3Sderaadt 				display_partition(stdout, lp, i, 0, 0);
1325af98caf3Sderaadt 				display_partition(stdout, lp, j, 0, 0);
13266fe57b42Smillert 
13276fe57b42Smillert 				/* Did they ask us to resolve it ourselves? */
132896a888c6Smillert 				if (resolve != 1) {
1329f0b4d0a9Smillert 					(void)free(spp);
13306fe57b42Smillert 					return(1);
1331f0b4d0a9Smillert 				}
13326fe57b42Smillert 
1333e6aa8bafSmillert 				/* Get partition to disable or ^D */
1334e6aa8bafSmillert 				do {
1335616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
13366fe57b42Smillert 					    'a' + i, 'a' + j);
1337e6aa8bafSmillert 					buf[0] = '\0';
1338616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1339616cd1c4Smillert 						putchar('\n');
1340e6aa8bafSmillert 						return(1);	/* ^D */
1341616cd1c4Smillert 					}
1342e6aa8bafSmillert 					c = buf[0] - 'a';
1343e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1344e6aa8bafSmillert 				    c != i && c != j);
1345e6aa8bafSmillert 
1346e6aa8bafSmillert 				/* Mark the selected one as unused */
13476fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
13486fe57b42Smillert 				*freep += lp->d_partitions[c].p_size;
1349e6aa8bafSmillert 				(void)free(spp);
1350e6aa8bafSmillert 				return(has_overlap(lp, freep, resolve));
13516fe57b42Smillert 			}
13526fe57b42Smillert 		}
13536fe57b42Smillert 	}
1354f0b4d0a9Smillert 
1355f0b4d0a9Smillert 	(void)free(spp);
1356e6aa8bafSmillert 	return(0);
13576fe57b42Smillert }
13586fe57b42Smillert 
13596fe57b42Smillert void
13606fe57b42Smillert edit_parms(lp, freep)
13616fe57b42Smillert 	struct disklabel *lp;
13626fe57b42Smillert 	u_int32_t *freep;
13636fe57b42Smillert {
13646fe57b42Smillert 	char *p;
13656fe57b42Smillert 	u_int32_t ui;
136696a888c6Smillert 	struct disklabel oldlabel = *lp;
13676fe57b42Smillert 
1368ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
13696fe57b42Smillert 
13700f820bbbSmillert 	/* disk type */
13710f820bbbSmillert 	for (;;) {
13720f820bbbSmillert 		p = getstring(lp, "disk type",
137341282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
137441282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
137596a888c6Smillert 		if (p == NULL) {
137696a888c6Smillert 			fputs("Command aborted\n", stderr);
137796a888c6Smillert 			return;
137896a888c6Smillert 		}
137941282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
138041282a2aSmillert 			ui = DTYPE_ESDI;
138141282a2aSmillert 		else
138241282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
138341282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13840f820bbbSmillert 				;
13850f820bbbSmillert 		if (ui < DKMAXTYPES) {
13860f820bbbSmillert 			break;
13870f820bbbSmillert 		} else {
13880f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13890f820bbbSmillert 			fputs("Valid types are: ", stdout);
13900f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13910f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13920f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13930f820bbbSmillert 					fputs(", ", stdout);
13940f820bbbSmillert 			}
13950f820bbbSmillert 			putchar('\n');
13960f820bbbSmillert 		}
13970f820bbbSmillert 	}
13980f820bbbSmillert 	lp->d_type = ui;
13990f820bbbSmillert 
14006fe57b42Smillert 	/* pack/label id */
14016fe57b42Smillert 	p = getstring(lp, "label name",
14026fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
14036fe57b42Smillert 	    lp->d_packname);
140496a888c6Smillert 	if (p == NULL) {
140596a888c6Smillert 		fputs("Command aborted\n", stderr);
140696a888c6Smillert 		*lp = oldlabel;		/* undo damage */
140796a888c6Smillert 		return;
140896a888c6Smillert 	}
14096fe57b42Smillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1);
14106fe57b42Smillert 	lp->d_packname[sizeof(lp->d_packname) - 1] = '\0';
14116fe57b42Smillert 
14126fe57b42Smillert 	/* sectors/track */
14136fe57b42Smillert 	for (;;) {
14146fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
14156fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
14166fe57b42Smillert 		    lp->d_nsectors, 0);
141796a888c6Smillert 		if (ui == UINT_MAX - 1) {
141896a888c6Smillert 			fputs("Command aborted\n", stderr);
141996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
142096a888c6Smillert 			return;
142196a888c6Smillert 		} if (ui == UINT_MAX)
14226fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14236fe57b42Smillert 		else
14246fe57b42Smillert 			break;
14256fe57b42Smillert 	}
14266fe57b42Smillert 	lp->d_nsectors = ui;
14276fe57b42Smillert 
14286fe57b42Smillert 	/* tracks/cylinder */
14296fe57b42Smillert 	for (;;) {
14306fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
14316fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
14326fe57b42Smillert 		    lp->d_ntracks, 0);
143396a888c6Smillert 		if (ui == UINT_MAX - 1) {
143496a888c6Smillert 			fputs("Command aborted\n", stderr);
143596a888c6Smillert 			*lp = oldlabel;		/* undo damage */
143696a888c6Smillert 			return;
143796a888c6Smillert 		} else if (ui == UINT_MAX)
14386fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14396fe57b42Smillert 		else
14406fe57b42Smillert 			break;
14416fe57b42Smillert 	}
14426fe57b42Smillert 	lp->d_ntracks = ui;
14436fe57b42Smillert 
14446fe57b42Smillert 	/* sectors/cylinder */
1445148b6188Smillert 	for (;;) {
1446148b6188Smillert 		ui = getuint(lp, 0, "sectors/cylinder",
1447148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
1448148b6188Smillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 0);
144996a888c6Smillert 		if (ui == UINT_MAX - 1) {
145096a888c6Smillert 			fputs("Command aborted\n", stderr);
145196a888c6Smillert 			*lp = oldlabel;		/* undo damage */
145296a888c6Smillert 			return;
145396a888c6Smillert 		} else if (ui == UINT_MAX)
1454148b6188Smillert 			fputs("Invalid entry\n", stderr);
1455148b6188Smillert 		else
1456148b6188Smillert 			break;
1457148b6188Smillert 	}
1458148b6188Smillert 	lp->d_secpercyl = ui;
14596fe57b42Smillert 
14606fe57b42Smillert 	/* number of cylinders */
14616fe57b42Smillert 	for (;;) {
14626fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
14636fe57b42Smillert 		    "The total number of cylinders on the disk.",
14646fe57b42Smillert 		    lp->d_ncylinders, lp->d_ncylinders, 0);
146596a888c6Smillert 		if (ui == UINT_MAX - 1) {
146696a888c6Smillert 			fputs("Command aborted\n", stderr);
146796a888c6Smillert 			*lp = oldlabel;		/* undo damage */
146896a888c6Smillert 			return;
146996a888c6Smillert 		} else if (ui == UINT_MAX)
14706fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14716fe57b42Smillert 		else
14726fe57b42Smillert 			break;
14736fe57b42Smillert 	}
14746fe57b42Smillert 	lp->d_ncylinders = ui;
14756fe57b42Smillert 
14766fe57b42Smillert 	/* total sectors */
14776fe57b42Smillert 	for (;;) {
14786fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
14796fe57b42Smillert 		    "The total number of sectors on the disk.",
14806fe57b42Smillert 		    lp->d_secperunit ? lp->d_secperunit :
14816fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders,
14826fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders, 0);
148396a888c6Smillert 		if (ui == UINT_MAX - 1) {
148496a888c6Smillert 			fputs("Command aborted\n", stderr);
148596a888c6Smillert 			*lp = oldlabel;		/* undo damage */
148696a888c6Smillert 			return;
148796a888c6Smillert 		} else if (ui == UINT_MAX)
14886fe57b42Smillert 			fputs("Invalid entry\n", stderr);
148996a888c6Smillert 		else if (ui > lp->d_secperunit &&
149096a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14916fe57b42Smillert 			/* grow free count */
14926fe57b42Smillert 			*freep += ui - lp->d_secperunit;
1493f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1494f98aebd4Smillert 			    "partition.");
14956fe57b42Smillert 			break;
149696a888c6Smillert 		} else if (ui < lp->d_secperunit &&
149796a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14986fe57b42Smillert 			/* shrink free count */
14996fe57b42Smillert 			if (lp->d_secperunit - ui > *freep)
15006fe57b42Smillert 				fprintf(stderr,
15016fe57b42Smillert 				    "Not enough free space to shrink by %u "
15026fe57b42Smillert 				    "sectors (only %u sectors left)\n",
15036fe57b42Smillert 				    lp->d_secperunit - ui, *freep);
15046fe57b42Smillert 			else {
15056fe57b42Smillert 				*freep -= lp->d_secperunit - ui;
15066fe57b42Smillert 				break;
15076fe57b42Smillert 			}
15086fe57b42Smillert 		} else
15096fe57b42Smillert 			break;
15106fe57b42Smillert 	}
151196a888c6Smillert 	/* Adjust ending_sector if necesary. */
151296a888c6Smillert 	if (ending_sector > ui)
151396a888c6Smillert 		ending_sector = ui;
15146fe57b42Smillert 	lp->d_secperunit = ui;
15156fe57b42Smillert 
15166fe57b42Smillert 	/* rpm */
15176fe57b42Smillert 	for (;;) {
15186fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1519a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
15206fe57b42Smillert 		  lp->d_rpm, lp->d_rpm, 0);
152196a888c6Smillert 		if (ui == UINT_MAX - 1) {
152296a888c6Smillert 			fputs("Command aborted\n", stderr);
152396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
152496a888c6Smillert 			return;
152596a888c6Smillert 		} else if (ui == UINT_MAX)
15266fe57b42Smillert 			fputs("Invalid entry\n", stderr);
15276fe57b42Smillert 		else
15286fe57b42Smillert 			break;
15296fe57b42Smillert 	}
15306fe57b42Smillert 	lp->d_rpm = ui;
15316fe57b42Smillert }
1532a7e61405Smillert 
1533a7e61405Smillert struct partition **
1534a7e61405Smillert sort_partitions(lp, npart)
1535a7e61405Smillert 	struct disklabel *lp;
1536a7e61405Smillert 	u_int16_t *npart;
1537a7e61405Smillert {
1538a7e61405Smillert 	u_int16_t npartitions;
1539a7e61405Smillert 	struct partition **spp;
1540a7e61405Smillert 	int i;
1541a7e61405Smillert 
1542a7e61405Smillert 	/* How many "real" partitions do we have? */
1543a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1544a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1545a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1546a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1547a7e61405Smillert 			npartitions++;
1548a7e61405Smillert 	}
154996a888c6Smillert 	if (npartitions == 0) {
155096a888c6Smillert 		*npart = 0;
155196a888c6Smillert 		return(NULL);
155296a888c6Smillert 	}
1553a7e61405Smillert 
1554a7e61405Smillert 	/* Create an array of pointers to the partition data */
1555a7e61405Smillert 	if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL)
1556a7e61405Smillert 		errx(4, "out of memory");
1557a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1558a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1559a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1560a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1561a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1562a7e61405Smillert 	}
1563a7e61405Smillert 
1564a7e61405Smillert 	/*
1565a7e61405Smillert 	 * Sort the partitions based on starting offset.
1566a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1567a7e61405Smillert 	 */
1568a7e61405Smillert 	if (npartitions > 1)
1569a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1570a7e61405Smillert 		    partition_cmp))
1571a7e61405Smillert 			err(4, "failed to sort partition table");
1572a7e61405Smillert 
1573a7e61405Smillert 	*npart = npartitions;
1574a7e61405Smillert 	return(spp);
1575a7e61405Smillert }
15760f820bbbSmillert 
15770f820bbbSmillert /*
15780f820bbbSmillert  * Get a valid disk type if necessary.
15790f820bbbSmillert  */
15800f820bbbSmillert void
15810f820bbbSmillert getdisktype(lp, banner)
15820f820bbbSmillert 	struct disklabel *lp;
15830f820bbbSmillert 	char *banner;
15840f820bbbSmillert {
15850f820bbbSmillert 	int i;
15860f820bbbSmillert 	char *s;
15870f820bbbSmillert 
15880f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
15890f820bbbSmillert 		puts(banner);
15900f820bbbSmillert 		puts("Possible values are:");
1591eb5dd924Sderaadt 		printf("\"IDE\", ");
15920f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
15930f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
15940f820bbbSmillert 			if (i < DKMAXTYPES - 1)
15950f820bbbSmillert 				fputs(", ", stdout);
15960f820bbbSmillert 		}
15970f820bbbSmillert 		putchar('\n');
15980f820bbbSmillert 
15990f820bbbSmillert 		for (;;) {
16000f820bbbSmillert 			s = getstring(lp, "Disk type",
16015b412421Smillert 			    "What kind of disk is this?  Usually SCSI, ESDI, "
16025b412421Smillert 			    "ST506, or floppy (use ESDI for IDE).",
16030f820bbbSmillert 			    "SCSI");
160496a888c6Smillert 			if (s == NULL)
160596a888c6Smillert 				continue;
16065b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
16075b412421Smillert 				lp->d_type = DTYPE_ESDI;
16085b412421Smillert 				putchar('\n');
16095b412421Smillert 				return;
16105b412421Smillert 			}
16110f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
16120f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
16130f820bbbSmillert 					lp->d_type = i;
16140f820bbbSmillert 					putchar('\n');
16150f820bbbSmillert 					return;
16160f820bbbSmillert 				}
16170f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
16180f820bbbSmillert 			fputs("Valid types are: ", stdout);
16190f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
16200f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
16210f820bbbSmillert 				if (i < DKMAXTYPES - 1)
16220f820bbbSmillert 					fputs(", ", stdout);
16230f820bbbSmillert 			}
16240f820bbbSmillert 			putchar('\n');
16250f820bbbSmillert 		}
16260f820bbbSmillert 	}
16270f820bbbSmillert }
162896a888c6Smillert 
162996a888c6Smillert /*
163096a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
163196a888c6Smillert  * from the user.
16324793b14cSmillert  * XXX - should mention MBR values if DOSLABEL
163396a888c6Smillert  */
163496a888c6Smillert void
1635e8e8bdb7Sart set_bounds(lp, freep)
163696a888c6Smillert 	struct disklabel *lp;
1637e8e8bdb7Sart 	u_int32_t *freep;
163896a888c6Smillert {
163996a888c6Smillert 	u_int32_t ui, start_temp;
164096a888c6Smillert 
164196a888c6Smillert 	/* Starting sector */
164296a888c6Smillert 	do {
164396a888c6Smillert 		ui = getuint(lp, 0, "Starting sector",
164496a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
164596a888c6Smillert 		  starting_sector, lp->d_secperunit, 0);
164696a888c6Smillert 		if (ui == UINT_MAX - 1) {
164796a888c6Smillert 			fputs("Command aborted\n", stderr);
164896a888c6Smillert 			return;
164996a888c6Smillert 		}
165096a888c6Smillert 	} while (ui >= lp->d_secperunit);
165196a888c6Smillert 	start_temp = ui;
165296a888c6Smillert 
16534793b14cSmillert 	/* Size */
165496a888c6Smillert 	do {
1655f98aebd4Smillert 		ui = getuint(lp, 0, "Size ('*' for entire disk)",
1656f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1657f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
1658f98aebd4Smillert 		  lp->d_secperunit - start_temp, 0);
165996a888c6Smillert 		if (ui == UINT_MAX - 1) {
166096a888c6Smillert 			fputs("Command aborted\n", stderr);
166196a888c6Smillert 			return;
166296a888c6Smillert 		}
1663f98aebd4Smillert 	} while (ui > lp->d_secperunit - start_temp);
16644793b14cSmillert 	ending_sector = start_temp + ui;
166596a888c6Smillert 	starting_sector = start_temp;
1666e8e8bdb7Sart 
1667e8e8bdb7Sart 	/* Recalculate the free sectors */
1668c0bdc608Smillert 	editor_countfree(lp, freep);
166996a888c6Smillert }
167096a888c6Smillert 
167196a888c6Smillert /*
167296a888c6Smillert  * Return a list of the "chunks" of free space available
167396a888c6Smillert  */
167496a888c6Smillert struct diskchunk *
167596a888c6Smillert free_chunks(lp)
167696a888c6Smillert 	struct disklabel *lp;
167796a888c6Smillert {
167896a888c6Smillert 	u_int16_t npartitions;
167996a888c6Smillert 	struct partition **spp;
168096a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
168196a888c6Smillert 	int i, numchunks;
168296a888c6Smillert 
168396a888c6Smillert 	/* Sort the partitions based on offset */
168496a888c6Smillert 	spp = sort_partitions(lp, &npartitions);
168596a888c6Smillert 
168696a888c6Smillert 	/* If there are no partitions, it's all free. */
168796a888c6Smillert 	if (spp == NULL) {
168896a888c6Smillert 		chunks[0].start = 0;
168996a888c6Smillert 		chunks[0].stop = ending_sector;
169096a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
169196a888c6Smillert 		return(chunks);
169296a888c6Smillert 	}
169396a888c6Smillert 
169496a888c6Smillert 	/* Find chunks of free space */
169596a888c6Smillert 	numchunks = 0;
169696a888c6Smillert 	if (spp && spp[0]->p_offset > 0) {
169796a888c6Smillert 		chunks[0].start = 0;
169896a888c6Smillert 		chunks[0].stop = spp[0]->p_offset;
169996a888c6Smillert 		numchunks++;
170096a888c6Smillert 	}
170196a888c6Smillert 	for (i = 0; i < npartitions; i++) {
170296a888c6Smillert 		if (i + 1 < npartitions) {
170396a888c6Smillert 			if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) {
170496a888c6Smillert 				chunks[numchunks].start =
170596a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
170696a888c6Smillert 				chunks[numchunks].stop = spp[i+1]->p_offset;
170796a888c6Smillert 				numchunks++;
170896a888c6Smillert 			}
170996a888c6Smillert 		} else {
171096a888c6Smillert 			/* Last partition */
171196a888c6Smillert 			if (spp[i]->p_offset + spp[i]->p_size < lp->d_secperunit) {
171296a888c6Smillert 
171396a888c6Smillert 				chunks[numchunks].start =
171496a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
171596a888c6Smillert 				chunks[numchunks].stop = lp->d_secperunit;
171696a888c6Smillert 				numchunks++;
171796a888c6Smillert 			}
171896a888c6Smillert 		}
171996a888c6Smillert 	}
172096a888c6Smillert 
172196a888c6Smillert 	/* Terminate and return */
172296a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
172396a888c6Smillert 	(void)free(spp);
172496a888c6Smillert 	return(chunks);
172596a888c6Smillert }
17264793b14cSmillert 
17274793b14cSmillert /*
17284793b14cSmillert  * What is the OpenBSD portion of the disk?  Uses the MBR if applicable.
17294793b14cSmillert  */
17304793b14cSmillert void
17314793b14cSmillert find_bounds(lp)
17324793b14cSmillert 	struct disklabel *lp;
17334793b14cSmillert {
1734f98aebd4Smillert 	struct  partition *pp = &lp->d_partitions[2];
17354793b14cSmillert 
17364793b14cSmillert 	/* Defaults */
17374793b14cSmillert 	/* XXX - reserve a cylinder for hp300? */
17384793b14cSmillert 	starting_sector = 0;
17394793b14cSmillert 	ending_sector = lp->d_secperunit;
17404793b14cSmillert 
17414793b14cSmillert #ifdef DOSLABEL
1742aaa7b57dSderaadt 	/* If we have an MBR, use values from the OpenBSD/FreeBSD parition. */
1743aaa7b57dSderaadt 	if (dosdp && pp->p_size &&
1744aaa7b57dSderaadt 	    (dosdp->dp_typ == DOSPTYP_OPENBSD ||
1745aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_FREEBSD ||
1746aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_NETBSD)) {
17474793b14cSmillert 		starting_sector = get_le(&dosdp->dp_start);
17484793b14cSmillert 		ending_sector = starting_sector + get_le(&dosdp->dp_size);
17494793b14cSmillert 		printf("Treating sectors %u-%u as the OpenBSD portion of the "
17504793b14cSmillert 		    "disk.\nYou can use the 'b' command to change this.\n",
17514793b14cSmillert 		    starting_sector, ending_sector);
1752f98aebd4Smillert 		/*
1753f98aebd4Smillert 		 * XXX - check to see if any BSD/SWAP partitions go beyond
1754f98aebd4Smillert 		 *	 ending_sector and prompt to extend ending_sector if so.
1755f98aebd4Smillert 		 */
17564793b14cSmillert 	}
17574793b14cSmillert #endif
17584793b14cSmillert }
1759c0bdc608Smillert 
1760c0bdc608Smillert /*
1761c0bdc608Smillert  * Calculate free space.
1762c0bdc608Smillert  */
1763c0bdc608Smillert void
1764c0bdc608Smillert editor_countfree(lp, freep)
1765c0bdc608Smillert     struct disklabel *lp;
1766c0bdc608Smillert     u_int32_t *freep;
1767c0bdc608Smillert {
1768c0bdc608Smillert     struct partition *pp;
1769c0bdc608Smillert     int i;
1770c0bdc608Smillert 
1771c0bdc608Smillert     *freep = ending_sector - starting_sector;
1772c0bdc608Smillert     for (i = 0; i < lp->d_npartitions; i++) {
1773c0bdc608Smillert 	pp = &lp->d_partitions[i];
1774c0bdc608Smillert 	if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
1775c0bdc608Smillert 	    pp->p_size > 0 &&
1776c0bdc608Smillert 	    pp->p_offset + pp->p_size <= ending_sector &&
1777c0bdc608Smillert 	    pp->p_offset >= starting_sector)
1778c0bdc608Smillert 	    *freep -= pp->p_size;
1779c0bdc608Smillert     }
1780c0bdc608Smillert }
1781