xref: /openbsd/sbin/disklabel/editor.c (revision 617e6e4a)
1*617e6e4aSmillert /*	$OpenBSD: editor.c,v 1.43 1998/08/06 18:07:40 millert Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
4*617e6e4aSmillert  * Copyright (c) 1997-1998 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*617e6e4aSmillert static char rcsid[] = "$OpenBSD: editor.c,v 1.43 1998/08/06 18:07:40 millert Exp $";
326fe57b42Smillert #endif /* not lint */
336fe57b42Smillert 
346fe57b42Smillert #include <sys/types.h>
356fe57b42Smillert #include <sys/param.h>
366fe57b42Smillert #define	DKTYPENAMES
376fe57b42Smillert #include <sys/disklabel.h>
386fe57b42Smillert 
396fe57b42Smillert #include <ufs/ffs/fs.h>
406fe57b42Smillert 
416fe57b42Smillert #include <ctype.h>
426fe57b42Smillert #include <err.h>
436fe57b42Smillert #include <errno.h>
446fe57b42Smillert #include <string.h>
45803ff7d5Smillert #include <libgen.h>
466fe57b42Smillert #include <stdio.h>
476fe57b42Smillert #include <stdlib.h>
486fe57b42Smillert #include <unistd.h>
496fe57b42Smillert 
504793b14cSmillert #include "pathnames.h"
514793b14cSmillert 
526fe57b42Smillert /* flags for getuint() */
536fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
546fe57b42Smillert #define	DO_ROUNDING	0x00000002
556fe57b42Smillert 
56f98aebd4Smillert #ifndef NUMBOOT
57f98aebd4Smillert #define NUMBOOT 0
58f98aebd4Smillert #endif
59f98aebd4Smillert 
6096a888c6Smillert /* structure to describe a portion of a disk */
6196a888c6Smillert struct diskchunk {
6296a888c6Smillert 	u_int32_t start;
6396a888c6Smillert 	u_int32_t stop;
6496a888c6Smillert };
6596a888c6Smillert 
666fe57b42Smillert void	edit_parms __P((struct disklabel *, u_int32_t *));
67803ff7d5Smillert int	editor __P((struct disklabel *, int, char *));
686fe57b42Smillert void	editor_add __P((struct disklabel *, u_int32_t *, char *));
696fe57b42Smillert void	editor_change __P((struct disklabel *, u_int32_t *, char *));
70c0bdc608Smillert void	editor_countfree __P((struct disklabel *, u_int32_t *));
71*617e6e4aSmillert void	editor_delete __P((struct disklabel *, u_int32_t *, char *));
72*617e6e4aSmillert void	editor_display __P((struct disklabel *, u_int32_t *, char));
73*617e6e4aSmillert void	editor_help __P((char *));
74*617e6e4aSmillert void	editor_modify __P((struct disklabel *, u_int32_t *, char *));
756fe57b42Smillert char	*getstring __P((struct disklabel *, char *, char *, char *));
766fe57b42Smillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int));
776fe57b42Smillert int	has_overlap __P((struct disklabel *, u_int32_t *, int));
786fe57b42Smillert void	make_contiguous __P((struct disklabel *));
7996a888c6Smillert u_int32_t next_offset __P((struct disklabel *, struct partition *));
806fe57b42Smillert int	partition_cmp __P((const void *, const void *));
81a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));
82803ff7d5Smillert void	getdisktype __P((struct disklabel *, char *, char *));
8396a888c6Smillert void	find_bounds __P((struct disklabel *));
84e8e8bdb7Sart void	set_bounds __P((struct disklabel *, u_int32_t *));
8596a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *));
8696a888c6Smillert 
8796a888c6Smillert static u_int32_t starting_sector;
8896a888c6Smillert static u_int32_t ending_sector;
896fe57b42Smillert 
906fe57b42Smillert /* from disklabel.c */
916fe57b42Smillert int	checklabel __P((struct disklabel *));
926fe57b42Smillert void	display __P((FILE *, struct disklabel *));
93af98caf3Sderaadt void	display_partition __P((FILE *, struct disklabel *, int, char, int));
94af98caf3Sderaadt int	width_partition __P((struct disklabel *, int));
95af98caf3Sderaadt 
966fe57b42Smillert struct disklabel *readlabel __P((int));
976fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int));
986fe57b42Smillert int	writelabel __P((int, char *, struct disklabel *));
996fe57b42Smillert extern	char *bootarea, *specname;
10069220492Smillert extern	int donothing;
1014793b14cSmillert #ifdef DOSLABEL
1024793b14cSmillert struct dos_partition *dosdp;	/* DOS partition, if found */
1034793b14cSmillert #endif
1046fe57b42Smillert 
1056fe57b42Smillert /*
1066fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
1076fe57b42Smillert  */
1086fe57b42Smillert int
109803ff7d5Smillert editor(lp, f, dev)
1106fe57b42Smillert 	struct disklabel *lp;
1116fe57b42Smillert 	int f;
112803ff7d5Smillert 	char *dev;
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" */
121803ff7d5Smillert 	getdisktype(&label, "You need to specify a type for this disk.", dev);
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 
14955403f76Smillert 	/* Set d_bbsize and d_sbsize as neccesary */
15055403f76Smillert 	if (strcmp(label.d_packname, "fictitious") == 0) {
15155403f76Smillert 		if (label.d_bbsize == 0)
15255403f76Smillert 			label.d_bbsize = BBSIZE;
15355403f76Smillert 		if (label.d_sbsize == 0)
15455403f76Smillert 			label.d_sbsize = SBSIZE;
15555403f76Smillert 	}
156f98aebd4Smillert 
157440b1d70Smillert 	/* Interleave must be >= 1 */
158440b1d70Smillert 	if (label.d_interleave == 0)
159440b1d70Smillert 		label.d_interleave = 1;
160440b1d70Smillert 
16196a888c6Smillert 	puts("\nInitial label editor (enter '?' for help at any prompt)");
1626fe57b42Smillert 	lastlabel = label;
1636fe57b42Smillert 	for (;;) {
1646fe57b42Smillert 		fputs("> ", stdout);
1656fe57b42Smillert 		fflush(stdout);
1666fe57b42Smillert 		rewind(stdin);
1676e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1686e0becc5Smillert 			putchar('\n');
1696e0becc5Smillert 			buf[0] = 'q';
1706e0becc5Smillert 			buf[1] = '\0';
1716e0becc5Smillert 		}
172260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
173260513deSmillert 			continue;
174260513deSmillert 		arg = strtok(NULL, " \t\r\n");
1756fe57b42Smillert 
1766fe57b42Smillert 		switch (*cmd) {
1776fe57b42Smillert 
1786fe57b42Smillert 		case '?':
179ea37abd3Sderaadt 		case 'h':
180*617e6e4aSmillert 			editor_help(arg ? arg : "");
1816fe57b42Smillert 			break;
1826fe57b42Smillert 
1836fe57b42Smillert 		case 'a':
1846fe57b42Smillert 			tmplabel = lastlabel;
1856fe57b42Smillert 			lastlabel = label;
18696a888c6Smillert 			editor_add(&label, &freesectors, arg);
18796a888c6Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
18896a888c6Smillert 				lastlabel = tmplabel;
18996a888c6Smillert 			break;
19096a888c6Smillert 
19196a888c6Smillert 		case 'b':
19296a888c6Smillert 			tmplabel = lastlabel;
19396a888c6Smillert 			lastlabel = label;
194e8e8bdb7Sart 			set_bounds(&label, &freesectors);
1956fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
1966fe57b42Smillert 				lastlabel = tmplabel;
1976fe57b42Smillert 			break;
1986fe57b42Smillert 
1996fe57b42Smillert 		case 'c':
2006fe57b42Smillert 			tmplabel = lastlabel;
2016fe57b42Smillert 			lastlabel = label;
20296a888c6Smillert 			editor_change(&label, &freesectors, arg);
2036fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2046fe57b42Smillert 				lastlabel = tmplabel;
2056fe57b42Smillert 			break;
2066fe57b42Smillert 
2076fe57b42Smillert 		case 'd':
2086fe57b42Smillert 			tmplabel = lastlabel;
2096fe57b42Smillert 			lastlabel = label;
21096a888c6Smillert 			editor_delete(&label, &freesectors, arg);
2116fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2126fe57b42Smillert 				lastlabel = tmplabel;
2136fe57b42Smillert 			break;
2146fe57b42Smillert 
2156fe57b42Smillert 		case 'm':
2166fe57b42Smillert 			tmplabel = lastlabel;
2176fe57b42Smillert 			lastlabel = label;
21896a888c6Smillert 			editor_modify(&label, &freesectors, arg);
2196fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2206fe57b42Smillert 				lastlabel = tmplabel;
2216fe57b42Smillert 			break;
2226fe57b42Smillert 
2236fe57b42Smillert 		case 'p':
22496a888c6Smillert 			editor_display(&label, &freesectors, arg ? *arg : 0);
2256fe57b42Smillert 			break;
2266fe57b42Smillert 
2275d12b01bSderaadt 		case 'M':
2284793b14cSmillert 			fp = popen(_PATH_LESS, "w");
2295d12b01bSderaadt 			if (fp) {
2305d12b01bSderaadt 				extern char manpage[];
2315d12b01bSderaadt 
2325d12b01bSderaadt 				(void) fwrite(manpage, strlen(manpage), 1, fp);
2335d12b01bSderaadt 				pclose(fp);
2345d12b01bSderaadt 			}
2355d12b01bSderaadt 			break;
2365d12b01bSderaadt 
2376fe57b42Smillert 		case 'q':
23869220492Smillert 			if (donothing) {
23969220492Smillert 				puts("In no change mode, not writing label.");
24069220492Smillert 				return(1);
24169220492Smillert 			}
2426fe57b42Smillert 			if (memcmp(lp, &label, sizeof(label)) == 0) {
2436fe57b42Smillert 				puts("No changes.");
2446fe57b42Smillert 				return(1);
2456fe57b42Smillert 			}
2466fe57b42Smillert 			do {
2476fe57b42Smillert 				arg = getstring(lp, "Save changes?",
2486fe57b42Smillert 				    "Save changes you have made to the label?",
2496fe57b42Smillert 				    "n");
25096a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
25196a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
2526fe57b42Smillert 				*lp = label;
2536fe57b42Smillert 				if (writelabel(f, bootarea, lp) == 0)
2546fe57b42Smillert 					return(0);
2556fe57b42Smillert 			}
2566fe57b42Smillert 			return(1);
2576fe57b42Smillert 			/* NOTREACHED */
2586fe57b42Smillert 			break;
2596fe57b42Smillert 
260c0bdc608Smillert 		case 'r':
261c0bdc608Smillert 		    /* Recalculate free space */
262c0bdc608Smillert 		    editor_countfree(&label, &freesectors);
263c0bdc608Smillert 		    puts("Recalculated free space.");
264c0bdc608Smillert 		    break;
265c0bdc608Smillert 
2666fe57b42Smillert 		case 's':
2676fe57b42Smillert 			if (arg == NULL) {
268260513deSmillert 				arg = getstring(lp, "Filename",
2696fe57b42Smillert 				    "Name of the file to save label into.",
2706fe57b42Smillert 				    NULL);
27196a888c6Smillert 				if (arg == NULL && *arg == '\0')
2726fe57b42Smillert 					break;
2736fe57b42Smillert 			}
2746fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
2756fe57b42Smillert 				warn("cannot open %s", arg);
2766fe57b42Smillert 			} else {
2776fe57b42Smillert 				display(fp, &label);
2786fe57b42Smillert 				(void)fclose(fp);
2796fe57b42Smillert 			}
2806fe57b42Smillert 			break;
2816fe57b42Smillert 
2826fe57b42Smillert 		case 'u':
2836fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0) {
2846fe57b42Smillert 				puts("Nothing to undo!");
2856fe57b42Smillert 			} else {
2866fe57b42Smillert 				tmplabel = label;
2876fe57b42Smillert 				label = lastlabel;
2886fe57b42Smillert 				lastlabel = tmplabel;
289c0bdc608Smillert 				/* Recalculate free space */
290c0bdc608Smillert 				editor_countfree(&label, &freesectors);
2916fe57b42Smillert 				puts("Last change undone.");
2926fe57b42Smillert 			}
2936fe57b42Smillert 			break;
2946fe57b42Smillert 
295040947cfSmillert 		case 'w':
296040947cfSmillert 			if (donothing)
297040947cfSmillert 				puts("In no change mode, not writing label.");
298040947cfSmillert 			else if (memcmp(lp, &label, sizeof(label)) == 0)
299040947cfSmillert 				puts("No changes.");
300040947cfSmillert 			else if (writelabel(f, bootarea, &label) != 0)
301040947cfSmillert 				warnx("unable to write label");
3025af08e9cSmillert 			else
3035af08e9cSmillert 				*lp = label;
304040947cfSmillert 			break;
305040947cfSmillert 
3066fe57b42Smillert 		case 'x':
3076fe57b42Smillert 			return(1);
3086fe57b42Smillert 			break;
3096fe57b42Smillert 
3106fe57b42Smillert 		case '\n':
3116fe57b42Smillert 			break;
3126fe57b42Smillert 
3136fe57b42Smillert 		case 'e':
3146fe57b42Smillert 			tmplabel = lastlabel;
3156fe57b42Smillert 			lastlabel = label;
31696a888c6Smillert 			edit_parms(&label, &freesectors);
3176fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
3186fe57b42Smillert 				lastlabel = tmplabel;
3196fe57b42Smillert 			break;
3206fe57b42Smillert 
3216fe57b42Smillert 		default:
3226fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
3236fe57b42Smillert 			break;
3246fe57b42Smillert 		}
3256fe57b42Smillert 	}
3266fe57b42Smillert }
3276fe57b42Smillert 
3286fe57b42Smillert /*
3296fe57b42Smillert  * Add a new partition.
3306fe57b42Smillert  */
3316fe57b42Smillert void
3326fe57b42Smillert editor_add(lp, freep, p)
3336fe57b42Smillert 	struct disklabel *lp;
3346fe57b42Smillert 	u_int32_t *freep;
3356fe57b42Smillert 	char *p;
3366fe57b42Smillert {
33796a888c6Smillert 	struct partition *pp;
33896a888c6Smillert 	struct diskchunk *chunks;
3396fe57b42Smillert 	char buf[BUFSIZ];
3406fe57b42Smillert 	int i, partno;
34196a888c6Smillert 	u_int32_t ui, old_offset, old_size;
3426fe57b42Smillert 
3436fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
3446fe57b42Smillert 	if (*freep == 0) {
3456fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
3466fe57b42Smillert 		    stderr);
3476fe57b42Smillert 		return;
3486fe57b42Smillert 	}
3496fe57b42Smillert 
3506fe57b42Smillert 	/* XXX - make more like other editor_* */
3516fe57b42Smillert 	if (p != NULL) {
3526fe57b42Smillert 		partno = p[0] - 'a';
353e6ab932bSmillert 		if (partno < 0 || partno == 2 || partno >= MAXPARTITIONS) {
3546fe57b42Smillert 			fprintf(stderr,
355e6ab932bSmillert 			    "Partition must be between 'a' and '%c' "
356e6ab932bSmillert 			    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
3576fe57b42Smillert 			return;
35896a888c6Smillert 		} else if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
359f6299b35Sderaadt 		    lp->d_partitions[partno].p_size != 0) {
360f6299b35Sderaadt 			fprintf(stderr,
361f6299b35Sderaadt 			    "Partition '%c' exists.  Delete it first.\n",
362f6299b35Sderaadt 			    p[0]);
363f6299b35Sderaadt 			return;
3646fe57b42Smillert 		}
3656fe57b42Smillert 	} else {
3669c5f1350Smillert 		/* Find first unused partition that is not 'c' */
3676fe57b42Smillert 		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {
3689c5f1350Smillert 			if (lp->d_partitions[partno].p_size == 0 && partno != 2)
3696fe57b42Smillert 				break;
3706fe57b42Smillert 		}
3716fe57b42Smillert 		if (partno < MAXPARTITIONS) {
3726fe57b42Smillert 			buf[0] = partno + 'a';
3736fe57b42Smillert 			buf[1] = '\0';
3746fe57b42Smillert 			p = &buf[0];
3756fe57b42Smillert 		} else
3766fe57b42Smillert 			p = NULL;
3776fe57b42Smillert 		for (;;) {
3786fe57b42Smillert 			p = getstring(lp, "partition",
3796fe57b42Smillert 			    "The letter of the new partition, a - p.", p);
38096a888c6Smillert 			if (p == NULL)
38196a888c6Smillert 				return;
3826fe57b42Smillert 			partno = p[0] - 'a';
38396a888c6Smillert 			if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
38496a888c6Smillert 			    lp->d_partitions[partno].p_size != 0) {
38596a888c6Smillert 				fprintf(stderr,
38696a888c6Smillert 				    "Partition '%c' already exists.\n", p[0]);
38796a888c6Smillert 			} else if (partno >= 0 && partno < MAXPARTITIONS)
3886fe57b42Smillert 				break;
3896fe57b42Smillert 			fprintf(stderr,
3906fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
3916fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
3926fe57b42Smillert 		}
3936fe57b42Smillert 	}
39496a888c6Smillert 
39596a888c6Smillert 	/* Increase d_npartitions if necesary */
39696a888c6Smillert 	if (partno >= lp->d_npartitions)
39796a888c6Smillert 		lp->d_npartitions = partno + 1;
39896a888c6Smillert 
39996a888c6Smillert 	/* Set defaults */
4006fe57b42Smillert 	pp = &lp->d_partitions[partno];
4016fe57b42Smillert 	if (partno >= lp->d_npartitions)
4026fe57b42Smillert 		lp->d_npartitions = partno + 1;
4036fe57b42Smillert 	memset(pp, 0, sizeof(*pp));
40496a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
4056fe57b42Smillert 	pp->p_fsize = 1024;
4066fe57b42Smillert 	pp->p_frag = 8;
4076fe57b42Smillert 	pp->p_cpg = 16;
40896a888c6Smillert 	pp->p_size = *freep;
40996a888c6Smillert 	pp->p_offset = next_offset(lp, pp);	/* must be computed last */
410f98aebd4Smillert #if NUMBOOT == 1
411f98aebd4Smillert 	/* Don't clobber boot blocks */
412f98aebd4Smillert 	if (pp->p_offset == 0) {
4138dddfaa0Smillert 		pp->p_offset = lp->d_secpercyl;
4148dddfaa0Smillert 		pp->p_size -= lp->d_secpercyl;
415f98aebd4Smillert 	}
416f98aebd4Smillert #endif
41796a888c6Smillert 	old_offset = pp->p_offset;
41896a888c6Smillert 	old_size = pp->p_size;
41996a888c6Smillert 
42096a888c6Smillert getoff1:
42196a888c6Smillert 	/* Get offset */
42296a888c6Smillert 	for (;;) {
42396a888c6Smillert 		ui = getuint(lp, partno, "offset",
42496a888c6Smillert 		   "Starting sector for this partition.", pp->p_offset,
42596a888c6Smillert 		   pp->p_offset, DO_CONVERSIONS |
42696a888c6Smillert 		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
42796a888c6Smillert 		if (ui == UINT_MAX - 1) {
42896a888c6Smillert 			fputs("Command aborted\n", stderr);
42996a888c6Smillert 			pp->p_size = 0;		/* effective delete */
43096a888c6Smillert 			return;
43196a888c6Smillert 		} else if (ui == UINT_MAX)
43296a888c6Smillert 			fputs("Invalid entry\n", stderr);
43396a888c6Smillert 		else if (ui < starting_sector)
43496a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
435f98aebd4Smillert 			    " at sector %u, you tried to add a partition at %u."
436f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
437f98aebd4Smillert 			    "of the OpenBSD portion.\n" , starting_sector, ui);
43896a888c6Smillert 		else if (ui >= ending_sector)
43996a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
440f98aebd4Smillert 			    "at sector %u, you tried to add a partition at %u."
441f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
442f98aebd4Smillert 			    "of the OpenBSD portion.\n", ending_sector, ui);
44396a888c6Smillert 		else
44496a888c6Smillert 			break;
44596a888c6Smillert 	}
44696a888c6Smillert 	pp->p_offset = ui;
44796a888c6Smillert 
44896a888c6Smillert 	/* Recompute recommended size based on new offset */
44996a888c6Smillert 	ui = pp->p_fstype;
45096a888c6Smillert 	pp->p_fstype = FS_UNUSED;
45196a888c6Smillert 	chunks = free_chunks(lp);
45296a888c6Smillert 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
45396a888c6Smillert 		if (pp->p_offset >= chunks[i].start &&
45496a888c6Smillert 		    pp->p_offset < chunks[i].stop) {
45596a888c6Smillert 			pp->p_size = chunks[i].stop - pp->p_offset;
45696a888c6Smillert 			break;
45796a888c6Smillert 		}
45896a888c6Smillert 	}
45996a888c6Smillert 	pp->p_fstype = ui;
46096a888c6Smillert 
46196a888c6Smillert 	/* Get size */
46296a888c6Smillert 	for (;;) {
46396a888c6Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
46496a888c6Smillert 		    pp->p_size, *freep, DO_CONVERSIONS |
46596a888c6Smillert 		    ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ?
46696a888c6Smillert 		    DO_ROUNDING : 0));
46796a888c6Smillert 		if (ui == UINT_MAX - 1) {
46896a888c6Smillert 			fputs("Command aborted\n", stderr);
46996a888c6Smillert 			pp->p_size = 0;		/* effective delete */
47096a888c6Smillert 			return;
47196a888c6Smillert 		} else if (ui == UINT_MAX)
47296a888c6Smillert 			fputs("Invalid entry\n", stderr);
47396a888c6Smillert 		else if (ui > *freep)
47496a888c6Smillert 			/* XXX - prompt user to steal space from another partition */
47596a888c6Smillert 			fprintf(stderr,"Sorry, there are only %u sectors left\n",
47696a888c6Smillert 			    *freep);
47796a888c6Smillert 		else if (pp->p_offset + ui > ending_sector)
47896a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk ends "
47996a888c6Smillert 			    "at sector %u, you tried to add a partition ending "
480f98aebd4Smillert 			    "at sector %u.  You can use the 'b' command to "
481f98aebd4Smillert 			    "change the size of the OpenBSD portion.\n",
48296a888c6Smillert 			    ending_sector, pp->p_offset + ui);
48396a888c6Smillert 		else
48496a888c6Smillert 			break;
48596a888c6Smillert 	}
48696a888c6Smillert 	pp->p_size = ui;
48796a888c6Smillert 	if (pp->p_size == 0)
48896a888c6Smillert 		return;
48996a888c6Smillert 
49096a888c6Smillert 	/* Check for overlap */
49196a888c6Smillert 	if (has_overlap(lp, freep, 0)) {
4924793b14cSmillert 		printf("\nPlease re-enter an offset and size for partition "
4934793b14cSmillert 		    "%c.\n", 'a' + partno);
49496a888c6Smillert 		pp->p_offset = old_offset;
49596a888c6Smillert 		pp->p_size = old_size;
49696a888c6Smillert 		goto getoff1;		/* Yeah, I know... */
49796a888c6Smillert 	}
4986fe57b42Smillert 
4996fe57b42Smillert 	/* Get fstype */
5006fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
5016fe57b42Smillert 		p = getstring(lp, "FS type",
5026fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
5036fe57b42Smillert 		    fstypenames[pp->p_fstype]);
50496a888c6Smillert 		if (p == NULL) {
50596a888c6Smillert 			fputs("Command aborted\n", stderr);
50696a888c6Smillert 			pp->p_size = 0;		/* effective delete */
50796a888c6Smillert 			return;
50896a888c6Smillert 		}
5096fe57b42Smillert 		for (i = 0; i < FSMAXTYPES; i++) {
5106fe57b42Smillert 			if (!strcasecmp(p, fstypenames[i])) {
5116fe57b42Smillert 				pp->p_fstype = i;
5126fe57b42Smillert 				break;
5136fe57b42Smillert 			}
5146fe57b42Smillert 		}
5156fe57b42Smillert 		if (i >= FSMAXTYPES) {
5166fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
5176fe57b42Smillert 			pp->p_fstype = FS_OTHER;
5186fe57b42Smillert 		}
5196fe57b42Smillert 	} else {
5206fe57b42Smillert 		for (;;) {
5216fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
5226fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
5236fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
52496a888c6Smillert 			if (ui == UINT_MAX - 1) {
52596a888c6Smillert 				fputs("Command aborted\n", stderr);
52696a888c6Smillert 				pp->p_size = 0;		/* effective delete */
52796a888c6Smillert 				return;
52896a888c6Smillert 			} if (ui == UINT_MAX)
5296fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5306fe57b42Smillert 			else
5316fe57b42Smillert 				break;
5326fe57b42Smillert 		}
5336fe57b42Smillert 		pp->p_fstype = ui;
5346fe57b42Smillert 	}
5356fe57b42Smillert 
5366fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
5376fe57b42Smillert 		/* get fsize */
5386fe57b42Smillert 		for (;;) {
5396fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
5406fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
5416fe57b42Smillert 			    pp->p_fsize, pp->p_fsize, 0);
54296a888c6Smillert 			if (ui == UINT_MAX - 1) {
54396a888c6Smillert 				fputs("Command aborted\n", stderr);
54496a888c6Smillert 				pp->p_size = 0;		/* effective delete */
54596a888c6Smillert 				return;
54696a888c6Smillert 			} else if (ui == UINT_MAX)
5476fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5486fe57b42Smillert 			else
5496fe57b42Smillert 				break;
5506fe57b42Smillert 		}
5516fe57b42Smillert 		pp->p_fsize = ui;
5526fe57b42Smillert 		if (pp->p_fsize == 0)
5536fe57b42Smillert 			puts("Zero fragment size implies zero block size");
5546fe57b42Smillert 
5556fe57b42Smillert 		/* get bsize */
5566fe57b42Smillert 		/* XXX - do before frag size? */
5576fe57b42Smillert 		for (; pp->p_fsize > 0;) {
5586fe57b42Smillert 			ui = getuint(lp, partno, "block size",
5596fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
5606fe57b42Smillert 			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
5616fe57b42Smillert 			    0);
5626fe57b42Smillert 
5636fe57b42Smillert 			/* sanity checks */
56496a888c6Smillert 			if (ui == UINT_MAX - 1) {
56596a888c6Smillert 				fputs("Command aborted\n", stderr);
56696a888c6Smillert 				pp->p_size = 0;		/* effective delete */
56796a888c6Smillert 				return;
56896a888c6Smillert 			} else if (ui == UINT_MAX)
5696fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5706fe57b42Smillert 			else if (ui < getpagesize())
5716fe57b42Smillert 				fprintf(stderr,
5726fe57b42Smillert 				    "Error: block size must be at least as big "
5736fe57b42Smillert 				    "as page size (%d).\n", getpagesize());
5746fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
5756fe57b42Smillert 				fputs("Error: block size must be a multiple of the fragment size.\n", stderr);
5766fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
5776fe57b42Smillert 				fputs("Error: block size must be at least as big as fragment size.\n", stderr);
5786fe57b42Smillert 			else
5796fe57b42Smillert 				break;
5806fe57b42Smillert 		}
5816fe57b42Smillert 		pp->p_frag = ui / pp->p_fsize;
5826fe57b42Smillert 
5836fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
5846fe57b42Smillert 			/* get cpg */
5856fe57b42Smillert 			for (;;) {
5866fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
5876fe57b42Smillert 				    "Number of filesystem cylinders per group.  Usually 16 or 8.",
5886fe57b42Smillert 				    pp->p_cpg, pp->p_cpg, 0);
58996a888c6Smillert 				if (ui == UINT_MAX - 1) {
59096a888c6Smillert 					fputs("Command aborted\n", stderr);
59196a888c6Smillert 					pp->p_size = 0;	/* effective delete */
59296a888c6Smillert 					return;
59396a888c6Smillert 				} else if (ui == UINT_MAX)
5946fe57b42Smillert 					fputs("Invalid entry\n", stderr);
5956fe57b42Smillert 				else
5966fe57b42Smillert 					break;
5976fe57b42Smillert 			}
5986fe57b42Smillert 			pp->p_cpg = ui;
5996fe57b42Smillert 		}
6006fe57b42Smillert 	}
60196a888c6Smillert 	/* Update free sector count and make sure things stay contiguous. */
6026fe57b42Smillert 	*freep -= pp->p_size;
60396a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
60496a888c6Smillert 	    has_overlap(lp, freep, -1))
6056fe57b42Smillert 		make_contiguous(lp);
6066fe57b42Smillert }
6076fe57b42Smillert 
6086fe57b42Smillert /*
6096fe57b42Smillert  * Change an existing partition.
6106fe57b42Smillert  */
6116fe57b42Smillert void
6126fe57b42Smillert editor_modify(lp, freep, p)
6136fe57b42Smillert 	struct disklabel *lp;
6146fe57b42Smillert 	u_int32_t *freep;
6156fe57b42Smillert 	char *p;
6166fe57b42Smillert {
6176fe57b42Smillert 	struct partition origpart, *pp;
6186fe57b42Smillert 	u_int32_t ui;
6196fe57b42Smillert 	int partno;
6206fe57b42Smillert 
6216fe57b42Smillert 	/* Change which partition? */
6226fe57b42Smillert 	if (p == NULL) {
6236fe57b42Smillert 		p = getstring(lp, "partition to modify",
6246fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
6256fe57b42Smillert 	}
62696a888c6Smillert 	if (p == NULL) {
62796a888c6Smillert 		fputs("Command aborted\n", stderr);
62896a888c6Smillert 		return;
62996a888c6Smillert 	}
6306fe57b42Smillert 	partno = p[0] - 'a';
6316fe57b42Smillert 	pp = &lp->d_partitions[partno];
6326fe57b42Smillert 	origpart = lp->d_partitions[partno];
6336fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
6346fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
6356fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
6366fe57b42Smillert 		return;
6376fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
6386fe57b42Smillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
6396fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
6406fe57b42Smillert 		return;
6416fe57b42Smillert 	}
6426fe57b42Smillert 
6436fe57b42Smillert 	/* Get filesystem type */
6446fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
6456fe57b42Smillert 		p = getstring(lp, "FS type",
6466fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
6476fe57b42Smillert 		    fstypenames[pp->p_fstype]);
64896a888c6Smillert 		if (p == NULL) {
64996a888c6Smillert 			fputs("Command aborted\n", stderr);
65096a888c6Smillert 			pp->p_size = 0;		/* effective delete */
65196a888c6Smillert 			return;
65296a888c6Smillert 		}
6536fe57b42Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
6546fe57b42Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
6556fe57b42Smillert 				pp->p_fstype = ui;
6566fe57b42Smillert 				break;
6576fe57b42Smillert 			}
6586fe57b42Smillert 		}
6596fe57b42Smillert 		if (ui >= FSMAXTYPES) {
6606fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
6616fe57b42Smillert 			pp->p_fstype = FS_OTHER;
6626fe57b42Smillert 		}
6636fe57b42Smillert 	} else {
6646fe57b42Smillert 		for (;;) {
6656fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
6666fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
6676fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
66896a888c6Smillert 			if (ui == UINT_MAX - 1) {
66996a888c6Smillert 				fputs("Command aborted\n", stderr);
67096a888c6Smillert 				pp->p_size = 0;		/* effective delete */
67196a888c6Smillert 				return;
67296a888c6Smillert 			} else if (ui == UINT_MAX)
6736fe57b42Smillert 				fputs("Invalid entry\n", stderr);
6746fe57b42Smillert 			else
6756fe57b42Smillert 				break;
6766fe57b42Smillert 		}
6776fe57b42Smillert 		pp->p_fstype = ui;
6786fe57b42Smillert 	}
6796fe57b42Smillert 
6806fe57b42Smillert 	/* Did they disable/enable the partition? */
681229f463eSmillert 	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&
682229f463eSmillert 	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)
6836fe57b42Smillert 		*freep += origpart.p_size;
684229f463eSmillert 	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
685229f463eSmillert 	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {
6866fe57b42Smillert 		if (pp->p_size > *freep) {
6876fe57b42Smillert 			fprintf(stderr,
68896a888c6Smillert 			    "Warning, need %u sectors but there are only %u "
6896fe57b42Smillert 			    "free.  Setting size to %u.\n", pp->p_size, *freep,
6906fe57b42Smillert 			    *freep);
6916fe57b42Smillert 			pp->p_fstype = *freep;
6926fe57b42Smillert 			*freep = 0;
6936fe57b42Smillert 		} else
6946fe57b42Smillert 			*freep -= pp->p_size;		/* have enough space */
6956fe57b42Smillert 	}
6966fe57b42Smillert 
6976fe57b42Smillert getoff2:
6986fe57b42Smillert 	/* Get offset */
6996fe57b42Smillert 	for (;;) {
7006fe57b42Smillert 		ui = getuint(lp, partno, "offset",
7016fe57b42Smillert 		    "Starting sector for this partition.", pp->p_offset,
7026fe57b42Smillert 		    pp->p_offset, DO_CONVERSIONS |
7036fe57b42Smillert 		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
70496a888c6Smillert 		if (ui == UINT_MAX - 1) {
70596a888c6Smillert 			fputs("Command aborted\n", stderr);
70696a888c6Smillert 			*pp = origpart;		/* undo changes */
70796a888c6Smillert 			return;
70896a888c6Smillert 		} else if (ui == UINT_MAX)
7096fe57b42Smillert 			fputs("Invalid entry\n", stderr);
71096a888c6Smillert 		else if (partno != 2 && ui + ui < starting_sector) {
71196a888c6Smillert 			fprintf(stderr, "The OpenBSD portion of the disk starts"
712f98aebd4Smillert 			    " at sector %u, you tried to start at %u."
713f98aebd4Smillert 			    "  You can use the 'b' command to change the size "
714f98aebd4Smillert 			    "of the OpenBSD portion.\n", starting_sector, ui);
71596a888c6Smillert 		} else
7166fe57b42Smillert 			break;
7176fe57b42Smillert 	}
7186fe57b42Smillert 	pp->p_offset = ui;
7196fe57b42Smillert 
7206fe57b42Smillert 	/* Get size */
7216fe57b42Smillert 	/* XXX - this loop sucks */
7226fe57b42Smillert 	for (;;) {
7236fe57b42Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
7246fe57b42Smillert 		    pp->p_size, *freep, 1);
7256fe57b42Smillert 
7266fe57b42Smillert 		if (ui == pp->p_size)
7276fe57b42Smillert 			break;			/* no change */
7286fe57b42Smillert 
72996a888c6Smillert 		if (ui == UINT_MAX - 1) {
73096a888c6Smillert 			fputs("Command aborted\n", stderr);
73196a888c6Smillert 			*pp = origpart;		/* undo changes */
73296a888c6Smillert 			return;
73396a888c6Smillert 		} else if (ui == UINT_MAX) {
7346fe57b42Smillert 			fputs("Invalid entry\n", stderr);
7356fe57b42Smillert 			continue;
7366fe57b42Smillert 		} else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) {
7376fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
7386fe57b42Smillert 			    stderr);
7396fe57b42Smillert 			continue;
7406fe57b42Smillert 		}
7416fe57b42Smillert 
742229f463eSmillert 		if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) {
7436fe57b42Smillert 			pp->p_size = ui;	/* don't care what's free */
7446fe57b42Smillert 			break;
7456fe57b42Smillert 		} else {
7466fe57b42Smillert 			if (ui > pp->p_size + *freep)
7476fe57b42Smillert 				/* XXX - prompt user to steal space from another partition */
7486fe57b42Smillert 				fprintf(stderr,
74996a888c6Smillert 				    "Size may not be larger than %u sectors\n",
7506fe57b42Smillert 				    pp->p_size + *freep);
7516fe57b42Smillert 			else {
7526fe57b42Smillert 				*freep += pp->p_size - ui;
7536fe57b42Smillert 				pp->p_size = ui;
7546fe57b42Smillert 				break;
7556fe57b42Smillert 			}
7566fe57b42Smillert 		}
7576fe57b42Smillert 	}
758f98aebd4Smillert 	/* XXX - if (ui % lp->d_secpercyl == 0) make ui + offset on cyl bound */
759f98aebd4Smillert 	pp->p_size = ui;
7606fe57b42Smillert 	if (pp->p_size == 0)
7616fe57b42Smillert 		return;
7626fe57b42Smillert 
7636fe57b42Smillert 	/* Check for overlap and restore if not resolved */
7646fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
7656fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
7666fe57b42Smillert 		pp->p_offset = origpart.p_offset;
7676fe57b42Smillert 		pp->p_size = origpart.p_size;
7686fe57b42Smillert 		goto getoff2;		/* Yeah, I know... */
7696fe57b42Smillert 	}
7706fe57b42Smillert 
7716fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
7726fe57b42Smillert 		/* get fsize */
7736fe57b42Smillert 		for (;;) {
7746fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
7756fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
77637bb54cbSmillert 			    pp->p_fsize ? pp->p_fsize : 1024, 1024, 0);
77796a888c6Smillert 			if (ui == UINT_MAX - 1) {
77896a888c6Smillert 				fputs("Command aborted\n", stderr);
77996a888c6Smillert 				*pp = origpart;		/* undo changes */
78096a888c6Smillert 				return;
78196a888c6Smillert 			} else if (ui == UINT_MAX)
7826fe57b42Smillert 				fputs("Invalid entry\n", stderr);
7836fe57b42Smillert 			else
7846fe57b42Smillert 				break;
7856fe57b42Smillert 		}
7866fe57b42Smillert 		pp->p_fsize = ui;
7876fe57b42Smillert 		if (pp->p_fsize == 0)
7886fe57b42Smillert 			puts("Zero fragment size implies zero block size");
7896fe57b42Smillert 
7906fe57b42Smillert 		/* get bsize */
7916fe57b42Smillert 		for (; pp->p_fsize > 0;) {
7926fe57b42Smillert 			ui = getuint(lp, partno, "block size",
7936fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
79437bb54cbSmillert 			    pp->p_frag ? pp->p_fsize * pp->p_frag : 8192,
79537bb54cbSmillert 			    8192, 0);
7966fe57b42Smillert 
7976fe57b42Smillert 			/* sanity check */
79896a888c6Smillert 			if (ui == UINT_MAX - 1) {
79996a888c6Smillert 				fputs("Command aborted\n", stderr);
80096a888c6Smillert 				*pp = origpart;		/* undo changes */
80196a888c6Smillert 				return;
80296a888c6Smillert 			} else if (ui == UINT_MAX)
8036fe57b42Smillert 				fputs("Invalid entry\n", stderr);
8046fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
8056fe57b42Smillert 				puts("Error: block size must be a multiple of the fragment size.");
8066fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
8076fe57b42Smillert 				puts("Error: block size must be at least as big as fragment size.");
8086fe57b42Smillert 			else {
8096fe57b42Smillert 				pp->p_frag = ui / pp->p_fsize;
8106fe57b42Smillert 				break;
8116fe57b42Smillert 			}
8126fe57b42Smillert 		}
8136fe57b42Smillert 
8146fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
8156fe57b42Smillert 			/* get cpg */
8166fe57b42Smillert 			for (;;) {
8176fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
8186fe57b42Smillert 				    "Number of filesystem cylinders per group."
81937bb54cbSmillert 				    "  Usually 16 or 8.",
82037bb54cbSmillert 				    pp->p_cpg ? pp->p_cpg : 16, 16, 0);
82196a888c6Smillert 				if (ui == UINT_MAX - 1) {
82296a888c6Smillert 					fputs("Command aborted\n", stderr);
82396a888c6Smillert 					*pp = origpart;	/* undo changes */
82496a888c6Smillert 					return;
82596a888c6Smillert 				} else if (ui == UINT_MAX)
8266fe57b42Smillert 					fputs("Invalid entry\n", stderr);
8276fe57b42Smillert 				else
8286fe57b42Smillert 					break;
8296fe57b42Smillert 			}
8306fe57b42Smillert 			pp->p_cpg = ui;
8316fe57b42Smillert 		}
8326fe57b42Smillert 	}
8336fe57b42Smillert 
8346fe57b42Smillert 	/* Make sure things stay contiguous. */
83596a888c6Smillert 	if (pp->p_size + pp->p_offset > ending_sector ||
83696a888c6Smillert 	    has_overlap(lp, freep, -1))
8376fe57b42Smillert 		make_contiguous(lp);
8386fe57b42Smillert }
8396fe57b42Smillert 
8406fe57b42Smillert /*
8416fe57b42Smillert  * Delete an existing partition.
8426fe57b42Smillert  */
8436fe57b42Smillert void
8446fe57b42Smillert editor_delete(lp, freep, p)
8456fe57b42Smillert 	struct disklabel *lp;
8466fe57b42Smillert 	u_int32_t *freep;
8476fe57b42Smillert 	char *p;
8486fe57b42Smillert {
8496fe57b42Smillert 	int c;
8506fe57b42Smillert 
8516fe57b42Smillert 	if (p == NULL) {
8526fe57b42Smillert 		p = getstring(lp, "partition to delete",
8536fe57b42Smillert 		    "The letter of the partition to delete, a - p.", NULL);
8546fe57b42Smillert 	}
85596a888c6Smillert 	if (p == NULL) {
85696a888c6Smillert 		fputs("Command aborted\n", stderr);
85796a888c6Smillert 		return;
85896a888c6Smillert 	}
8596fe57b42Smillert 	c = p[0] - 'a';
8606fe57b42Smillert 	if (c < 0 || c >= lp->d_npartitions)
8616fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
8626fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
8636fe57b42Smillert 	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==
8646fe57b42Smillert 	    FS_UNUSED && lp->d_partitions[c].p_size == 0))
8656fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);
8666fe57b42Smillert 	else if (c == 2)
867*617e6e4aSmillert 		fputs(
868*617e6e4aSmillert "You may not delete the 'c' partition.  The 'c' partition must exist and\n"
869*617e6e4aSmillert "should span the entire disk.  By default it is of type 'unused' and so\n"
870*617e6e4aSmillert "does not take up any space.\n", stderr);
87196a888c6Smillert 	else if (lp->d_partitions[c].p_offset >= ending_sector ||
87296a888c6Smillert 	    lp->d_partitions[c].p_offset < starting_sector)
87396a888c6Smillert 		fprintf(stderr, "The OpenBSD portion of the disk ends at sector"
87496a888c6Smillert 		    " %u.\nYou can't remove a partition outside the OpenBSD "
875f98aebd4Smillert 		    "part of the disk.  You can use the 'b' command to change "
876f98aebd4Smillert 		    "the size of the OpenBSD portion.\n", ending_sector);
8776fe57b42Smillert 	else {
87896a888c6Smillert 		/* Update free sector count. */
8796fe57b42Smillert 		if (lp->d_partitions[c].p_fstype != FS_UNUSED &&
880229f463eSmillert 		    lp->d_partitions[c].p_fstype != FS_BOOT &&
8816fe57b42Smillert 		    lp->d_partitions[c].p_size != 0)
8826fe57b42Smillert 			*freep += lp->d_partitions[c].p_size;
8836fe57b42Smillert 
8846fe57b42Smillert 		/* Really delete it (as opposed to just setting to "unused") */
8856fe57b42Smillert 		(void)memset(&lp->d_partitions[c], 0,
8866fe57b42Smillert 		    sizeof(lp->d_partitions[c]));
8876fe57b42Smillert 	}
8886fe57b42Smillert }
8896fe57b42Smillert 
8906fe57b42Smillert /*
8916fe57b42Smillert  * Simplified display() for use with the builtin editor.
8926fe57b42Smillert  */
8936fe57b42Smillert void
8946fe57b42Smillert editor_display(lp, freep, unit)
8956fe57b42Smillert 	struct disklabel *lp;
8966fe57b42Smillert 	u_int32_t *freep;
8976fe57b42Smillert 	char unit;
8986fe57b42Smillert {
8996fe57b42Smillert 	int i;
900af98caf3Sderaadt 	int width;
9016fe57b42Smillert 
9026fe57b42Smillert 	printf("device: %s\n", specname);
9030f820bbbSmillert 	printf("type: %s\n", dktypenames[lp->d_type]);
9046fe57b42Smillert 	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
9056fe57b42Smillert 	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
9066fe57b42Smillert 	printf("bytes/sector: %ld\n", (long)lp->d_secsize);
9076fe57b42Smillert 	printf("sectors/track: %ld\n", (long)lp->d_nsectors);
9086fe57b42Smillert 	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);
9096fe57b42Smillert 	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);
9106fe57b42Smillert 	printf("cylinders: %ld\n", (long)lp->d_ncylinders);
9116fe57b42Smillert 	printf("total sectors: %ld\n", (long)lp->d_secperunit);
9126fe57b42Smillert 	printf("free sectors: %u\n", *freep);
9136fe57b42Smillert 	printf("rpm: %ld\n", (long)lp->d_rpm);
9146fe57b42Smillert 	printf("\n%d partitions:\n", lp->d_npartitions);
915af98caf3Sderaadt 	width = width_partition(lp, unit);
916af98caf3Sderaadt 	printf("#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n",
917af98caf3Sderaadt 		width, width, "size", width, width, "offset");
9186fe57b42Smillert 	for (i = 0; i < lp->d_npartitions; i++)
919af98caf3Sderaadt 		display_partition(stdout, lp, i, unit, width);
9206fe57b42Smillert }
9216fe57b42Smillert 
9226fe57b42Smillert /*
9236fe57b42Smillert  * Find the next reasonable starting offset and returns it.
92496a888c6Smillert  * Assumes there is a least one free sector left (returns 0 if not).
9256fe57b42Smillert  */
9266fe57b42Smillert u_int32_t
92796a888c6Smillert next_offset(lp, pp)
9286fe57b42Smillert 	struct disklabel *lp;
92996a888c6Smillert 	struct partition *pp;
9306fe57b42Smillert {
931f0b4d0a9Smillert 	struct partition **spp;
93296a888c6Smillert 	struct diskchunk *chunks;
933f0b4d0a9Smillert 	u_int16_t npartitions;
93496a888c6Smillert 	u_int32_t new_offset, new_size;
93596a888c6Smillert 	int i, good_offset;
9366fe57b42Smillert 
937a7e61405Smillert 	/* Get a sorted list of the partitions */
93896a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
93996a888c6Smillert 		return(0);
940f0b4d0a9Smillert 
94196a888c6Smillert 	new_offset = starting_sector;
942f0b4d0a9Smillert 	for (i = 0; i < npartitions; i++ ) {
94396a888c6Smillert 		/* Skip the partition for which we are finding an offset */
94496a888c6Smillert 		if (pp == spp[i])
94596a888c6Smillert 			continue;
94696a888c6Smillert 
9476fe57b42Smillert 		/*
9486fe57b42Smillert 		 * Is new_offset inside this partition?  If so,
94996a888c6Smillert 		 * make it the next sector after the partition ends.
9506fe57b42Smillert 		 */
9514793b14cSmillert 		if (spp[i]->p_offset + spp[i]->p_size < ending_sector &&
9524793b14cSmillert 		    ((new_offset >= spp[i]->p_offset &&
95396a888c6Smillert 		    new_offset < spp[i]->p_offset + spp[i]->p_size) ||
95496a888c6Smillert 		    (new_offset + pp->p_size >= spp[i]->p_offset && new_offset
9554793b14cSmillert 		    + pp->p_size <= spp[i]->p_offset + spp[i]->p_size)))
956f0b4d0a9Smillert 			new_offset = spp[i]->p_offset + spp[i]->p_size;
9576fe57b42Smillert 	}
9586fe57b42Smillert 
95996a888c6Smillert 	/* Did we find a suitable offset? */
96096a888c6Smillert 	for (good_offset = 1, i = 0; i < npartitions; i++ ) {
96196a888c6Smillert 		if (new_offset + pp->p_size >= spp[i]->p_offset &&
96296a888c6Smillert 		    new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) {
96396a888c6Smillert 			/* Nope */
96496a888c6Smillert 			good_offset = 0;
96596a888c6Smillert 			break;
96696a888c6Smillert 		}
96796a888c6Smillert 	}
96896a888c6Smillert 
96996a888c6Smillert 	/* Specified size is too big, find something that fits */
97096a888c6Smillert 	if (!good_offset) {
97196a888c6Smillert 		chunks = free_chunks(lp);
97296a888c6Smillert 		new_size = 0;
97396a888c6Smillert 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
97496a888c6Smillert 			if (chunks[i].stop - chunks[i].start > new_size) {
97596a888c6Smillert 			    new_size = chunks[i].stop - chunks[i].start;
97696a888c6Smillert 			    new_offset = chunks[i].start;
97796a888c6Smillert 			}
97896a888c6Smillert 		}
9794793b14cSmillert 		/* XXX - should do something intelligent if new_size == 0 */
98096a888c6Smillert 		pp->p_size = new_size;
98196a888c6Smillert 	}
98296a888c6Smillert 
983f0b4d0a9Smillert 	(void)free(spp);
9846fe57b42Smillert 	return(new_offset);
9856fe57b42Smillert }
9866fe57b42Smillert 
9876fe57b42Smillert /*
9886fe57b42Smillert  * Change the size of an existing partition.
9896fe57b42Smillert  */
9906fe57b42Smillert void
9916fe57b42Smillert editor_change(lp, freep, p)
9926fe57b42Smillert 	struct disklabel *lp;
9936fe57b42Smillert 	u_int32_t *freep;
9946fe57b42Smillert 	char *p;
9956fe57b42Smillert {
9966fe57b42Smillert 	int partno;
9976fe57b42Smillert 	u_int32_t newsize;
9986fe57b42Smillert 
9996fe57b42Smillert 	if (p == NULL) {
10006fe57b42Smillert 		p = getstring(lp, "partition to change size",
10016fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
10026fe57b42Smillert 	}
100396a888c6Smillert 	if (p == NULL) {
100496a888c6Smillert 		fputs("Command aborted\n", stderr);
100596a888c6Smillert 		return;
100696a888c6Smillert 	}
10076fe57b42Smillert 	partno = p[0] - 'a';
10086fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
10096fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
10106fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
10116fe57b42Smillert 		return;
10126fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
1013229f463eSmillert 	    lp->d_partitions[partno].p_size == 0) {
10146fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
10156fe57b42Smillert 		return;
10166fe57b42Smillert 	}
10176fe57b42Smillert 
10186fe57b42Smillert 	printf("Partition %c is currently %u sectors in size (%u free).\n",
10196fe57b42Smillert 	    partno + 'a', lp->d_partitions[partno].p_size, *freep);
1020229f463eSmillert 	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */
10216fe57b42Smillert 	newsize = getuint(lp, partno, "new size", "Size of the partition.  "
10226fe57b42Smillert 	    "You may also say +/- amount for a relative change.",
10236fe57b42Smillert 	    lp->d_partitions[partno].p_size,
10246fe57b42Smillert 	    lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS |
10256fe57b42Smillert 	    (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
102696a888c6Smillert 	if (newsize == UINT_MAX - 1) {
102796a888c6Smillert 		fputs("Command aborted\n", stderr);
102896a888c6Smillert 		return;
102996a888c6Smillert 	} else if (newsize == UINT_MAX) {
10306fe57b42Smillert 		fputs("Invalid entry\n", stderr);
10316fe57b42Smillert 		return;
10326fe57b42Smillert 	} else if (newsize == lp->d_partitions[partno].p_size)
10336fe57b42Smillert 		return;
10346fe57b42Smillert 
1035229f463eSmillert 	if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
1036229f463eSmillert 	    lp->d_partitions[partno].p_fstype != FS_BOOT) {
10376fe57b42Smillert 		if (newsize > lp->d_partitions[partno].p_size) {
10386fe57b42Smillert 			if (newsize - lp->d_partitions[partno].p_size > *freep) {
10396fe57b42Smillert 				fprintf(stderr,
10406fe57b42Smillert 				    "Only %u sectors free, you asked for %u\n",
10416fe57b42Smillert 				    *freep,
10426fe57b42Smillert 				    newsize - lp->d_partitions[partno].p_size);
10436fe57b42Smillert 				return;
10446fe57b42Smillert 			}
10456fe57b42Smillert 			*freep -= newsize - lp->d_partitions[partno].p_size;
10466fe57b42Smillert 		} else if (newsize < lp->d_partitions[partno].p_size) {
10476fe57b42Smillert 			*freep += lp->d_partitions[partno].p_size - newsize;
10486fe57b42Smillert 		}
10496fe57b42Smillert 	} else {
105096a888c6Smillert 		if (partno == 2 && newsize +
10516fe57b42Smillert 		    lp->d_partitions[partno].p_offset > lp->d_secperunit) {
10526fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
10536fe57b42Smillert 			    stderr);
10546fe57b42Smillert 			return;
10556fe57b42Smillert 		}
10566fe57b42Smillert 	}
10576fe57b42Smillert 	lp->d_partitions[partno].p_size = newsize;
105896a888c6Smillert 	if (newsize + lp->d_partitions[partno].p_offset > ending_sector ||
105996a888c6Smillert 	    has_overlap(lp, freep, -1))
10606fe57b42Smillert 		make_contiguous(lp);
10616fe57b42Smillert }
10626fe57b42Smillert 
10636fe57b42Smillert void
10646fe57b42Smillert make_contiguous(lp)
10656fe57b42Smillert 	struct disklabel *lp;
10666fe57b42Smillert {
10676fe57b42Smillert 	struct partition **spp;
10686fe57b42Smillert 	u_int16_t npartitions;
10696fe57b42Smillert 	int i;
10706fe57b42Smillert 
1071a7e61405Smillert 	/* Get a sorted list of the partitions */
107296a888c6Smillert 	if ((spp = sort_partitions(lp, &npartitions)) == NULL)
107396a888c6Smillert 		return;
10746fe57b42Smillert 
10756fe57b42Smillert 	/*
1076a7e61405Smillert 	 * Make everything contiguous but don't muck with start of the first one
107796a888c6Smillert 	 * or partitions not in the BSD part of the label.
10786fe57b42Smillert 	 */
107996a888c6Smillert 	for (i = 1; i < npartitions; i++) {
108096a888c6Smillert 		if (spp[i]->p_offset >= starting_sector ||
108196a888c6Smillert 		    spp[i]->p_offset < ending_sector)
108296a888c6Smillert 			spp[i]->p_offset =
108396a888c6Smillert 			    spp[i - 1]->p_offset + spp[i - 1]->p_size;
108496a888c6Smillert 	}
1085f0b4d0a9Smillert 
1086f0b4d0a9Smillert 	(void)free(spp);
10876fe57b42Smillert }
10886fe57b42Smillert 
10896fe57b42Smillert /*
10906fe57b42Smillert  * Sort the partitions based on starting offset.
10916fe57b42Smillert  * This assumes there can be no overlap.
10926fe57b42Smillert  */
10936fe57b42Smillert int
10946fe57b42Smillert partition_cmp(e1, e2)
10956fe57b42Smillert 	const void *e1, *e2;
10966fe57b42Smillert {
10976fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
10986fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
10996fe57b42Smillert 
11006fe57b42Smillert 	return((int)(p1->p_offset - p2->p_offset));
11016fe57b42Smillert }
11026fe57b42Smillert 
11036fe57b42Smillert char *
11046fe57b42Smillert getstring(lp, prompt, helpstring, oval)
11056fe57b42Smillert 	struct disklabel *lp;
11066fe57b42Smillert 	char *prompt;
11076fe57b42Smillert 	char *helpstring;
11086fe57b42Smillert 	char *oval;
11096fe57b42Smillert {
11106fe57b42Smillert 	static char buf[BUFSIZ];
11116fe57b42Smillert 	int n;
11126fe57b42Smillert 
11136fe57b42Smillert 	buf[0] = '\0';
11146fe57b42Smillert 	do {
11156fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
11166fe57b42Smillert 		fflush(stdout);
11176fe57b42Smillert 		rewind(stdin);
11186e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1119260513deSmillert 			buf[0] = '\0';
112096a888c6Smillert 			if (feof(stdin)) {
112196a888c6Smillert 				putchar('\n');
112296a888c6Smillert 				return(NULL);
112396a888c6Smillert 			}
11246e0becc5Smillert 		}
11256fe57b42Smillert 		n = strlen(buf);
11266fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11276fe57b42Smillert 			buf[--n] = '\0';
11286fe57b42Smillert 		if (buf[0] == '?')
11296fe57b42Smillert 			puts(helpstring);
11306fe57b42Smillert 		else if (oval != NULL && buf[0] == '\0') {
11316fe57b42Smillert 			(void)strncpy(buf, oval, sizeof(buf) - 1);
11326fe57b42Smillert 			buf[sizeof(buf) - 1] = '\0';
11336fe57b42Smillert 		}
11346fe57b42Smillert 	} while (buf[0] == '?');
11356fe57b42Smillert 
11366fe57b42Smillert 	return(&buf[0]);
11376fe57b42Smillert }
11386fe57b42Smillert 
11396fe57b42Smillert /*
11406fe57b42Smillert  * Returns UINT_MAX on error
11416fe57b42Smillert  * XXX - there are way too many parameters here.  Use inline helper functions
11426fe57b42Smillert  */
11436fe57b42Smillert u_int32_t
11446fe57b42Smillert getuint(lp, partno, prompt, helpstring, oval, maxval, flags)
11456fe57b42Smillert 	struct disklabel *lp;
11466fe57b42Smillert 	int partno;
11476fe57b42Smillert 	char *prompt;
11486fe57b42Smillert 	char *helpstring;
11496fe57b42Smillert 	u_int32_t oval;
11506fe57b42Smillert 	u_int32_t maxval;		/* XXX - used inconsistently */
11516fe57b42Smillert 	int flags;
11526fe57b42Smillert {
11536fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
11546fe57b42Smillert 	u_int32_t rval = oval;
11556fe57b42Smillert 	size_t n;
11566fe57b42Smillert 	int mult = 1;
115796a888c6Smillert 	double d;
11586fe57b42Smillert 
11596fe57b42Smillert 	buf[0] = '\0';
11606fe57b42Smillert 	do {
11616fe57b42Smillert 		printf("%s: [%u] ", prompt, oval);
11626fe57b42Smillert 		fflush(stdout);
11636fe57b42Smillert 		rewind(stdin);
11646e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
11656e0becc5Smillert 			buf[0] = '\0';
116696a888c6Smillert 			if (feof(stdin)) {
116796a888c6Smillert 				putchar('\n');
116896a888c6Smillert 				return(UINT_MAX - 1);
116996a888c6Smillert 			}
11706e0becc5Smillert 		}
11716fe57b42Smillert 		n = strlen(buf);
11726fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
11736fe57b42Smillert 			buf[--n] = '\0';
11746fe57b42Smillert 		if (buf[0] == '?')
11756fe57b42Smillert 			puts(helpstring);
11766fe57b42Smillert 	} while (buf[0] == '?');
11776fe57b42Smillert 
11786fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
11796fe57b42Smillert 		rval = maxval;
11806fe57b42Smillert 	} else {
11816fe57b42Smillert 		/* deal with units */
11826fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
11836fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
118496a888c6Smillert 				switch (tolower(buf[n-1])) {
11856fe57b42Smillert 
11866fe57b42Smillert 				case 'c':
11876fe57b42Smillert 					mult = lp->d_secpercyl;
11886fe57b42Smillert 					buf[--n] = '\0';
11896fe57b42Smillert 					break;
11906fe57b42Smillert 				case 'b':
11916fe57b42Smillert 					mult = -lp->d_secsize;
11926fe57b42Smillert 					buf[--n] = '\0';
11936fe57b42Smillert 					break;
11946fe57b42Smillert 				case 'k':
11956fe57b42Smillert 					mult = 1024 / lp->d_secsize;
11966fe57b42Smillert 					buf[--n] = '\0';
11976fe57b42Smillert 					break;
11986fe57b42Smillert 				case 'm':
11996fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
12006fe57b42Smillert 					buf[--n] = '\0';
12016fe57b42Smillert 					break;
12021a51a1eeSmillert 				case 'g':
12031a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
12041a51a1eeSmillert 					buf[--n] = '\0';
12051a51a1eeSmillert 					break;
12066fe57b42Smillert 				}
120796a888c6Smillert 			}
12086fe57b42Smillert 
12096fe57b42Smillert 			/* Did they give us an operator? */
12106fe57b42Smillert 			p = &buf[0];
12116fe57b42Smillert 			if (*p == '+' || *p == '-')
12126fe57b42Smillert 				operator = *p++;
12136fe57b42Smillert 
12146fe57b42Smillert 			endptr = p;
121596a888c6Smillert 			errno = 0;
121696a888c6Smillert 			d = strtod(p, &endptr);
121796a888c6Smillert 			if (errno == ERANGE)
121896a888c6Smillert 				rval = UINT_MAX;	/* too big/small */
121996a888c6Smillert 			else if (*endptr != '\0') {
12206fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
12216fe57b42Smillert 				rval = UINT_MAX;
12226fe57b42Smillert 			} else {
122396a888c6Smillert 				/* XXX - should check for overflow */
122496a888c6Smillert 				if (mult > 0)
122596a888c6Smillert 					rval = d * mult;
122696a888c6Smillert 				else
122796a888c6Smillert 					/* Negative mult means divide (fancy) */
122896a888c6Smillert 					rval = d / (-mult);
12296fe57b42Smillert 
123096a888c6Smillert 				/* Apply the operator */
12316fe57b42Smillert 				if (operator == '+')
12326fe57b42Smillert 					rval += oval;
12336fe57b42Smillert 				else if (operator == '-')
12346fe57b42Smillert 					rval = oval - rval;
12356fe57b42Smillert 			}
12366fe57b42Smillert 		}
12376fe57b42Smillert 	}
12386fe57b42Smillert 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
12396fe57b42Smillert 		u_int32_t cyls;
1240260513deSmillert 		/* XXX - should use maxsize and round down if too big */
12416fe57b42Smillert #ifdef CYLCHECK
12426fe57b42Smillert 		/* Always round to nearest cylinder, regardless of units */
12436fe57b42Smillert 		cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5);
12446fe57b42Smillert 		if (rval != cyls * lp->d_secpercyl) {
12456fe57b42Smillert 			rval = cyls * lp->d_secpercyl;
12466fe57b42Smillert 			printf("Rounding to nearest cylinder: %u\n", rval);
12476fe57b42Smillert 		}
12486fe57b42Smillert #else
124996a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
125096a888c6Smillert 		if (mult != 1) {
12516fe57b42Smillert 			cyls = (u_int32_t)((rval / (double)lp->d_secpercyl)
12526fe57b42Smillert 			    + 0.5);
12536fe57b42Smillert 			if (rval != cyls * lp->d_secpercyl) {
12546fe57b42Smillert 				rval = cyls * lp->d_secpercyl;
12556fe57b42Smillert 				printf("Rounding to nearest cylinder: %u\n",
12566fe57b42Smillert 				    rval);
12576fe57b42Smillert 			}
12586fe57b42Smillert 		}
12596fe57b42Smillert #endif
12606fe57b42Smillert 	}
12616fe57b42Smillert 
12626fe57b42Smillert 	return(rval);
12636fe57b42Smillert }
12646fe57b42Smillert 
12656fe57b42Smillert /*
12666fe57b42Smillert  * Check for partition overlap in lp and prompt the user
12676fe57b42Smillert  * to resolve the overlap if any is found.  Returns 1
12686fe57b42Smillert  * if unable to resolve, else 0.
12696fe57b42Smillert  */
12706fe57b42Smillert int
12716fe57b42Smillert has_overlap(lp, freep, resolve)
12726fe57b42Smillert 	struct disklabel *lp;
12736fe57b42Smillert 	u_int32_t *freep;
12746fe57b42Smillert 	int resolve;
12756fe57b42Smillert {
12766fe57b42Smillert 	struct partition **spp;
12776fe57b42Smillert 	u_int16_t npartitions;
1278e6aa8bafSmillert 	int c, i, j;
1279e6aa8bafSmillert 	char buf[BUFSIZ];
12806fe57b42Smillert 
1281a7e61405Smillert 	/* Get a sorted list of the partitions */
1282a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
12836fe57b42Smillert 
1284a7e61405Smillert 	if (npartitions < 2) {
1285a7e61405Smillert 		(void)free(spp);
12866fe57b42Smillert 		return(0);			/* nothing to do */
12876fe57b42Smillert 	}
12886fe57b42Smillert 
12896fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
12906fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
12916fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
12926fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
12936fe57b42Smillert 			if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) {
129496a888c6Smillert 				/* Don't print, just return */
129596a888c6Smillert 				if (resolve == -1) {
129696a888c6Smillert 					(void)free(spp);
129796a888c6Smillert 					return(1);
129896a888c6Smillert 				}
129996a888c6Smillert 
13006fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
13016fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
13026fe57b42Smillert 				    / sizeof(**spp);
13036fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
13046fe57b42Smillert 				    / sizeof(**spp);
13056fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
13066fe57b42Smillert 				    'a' + i, 'a' + j);
13076fe57b42Smillert 				puts("         size   offset    fstype   [fsize bsize   cpg]");
1308af98caf3Sderaadt 				display_partition(stdout, lp, i, 0, 0);
1309af98caf3Sderaadt 				display_partition(stdout, lp, j, 0, 0);
13106fe57b42Smillert 
13116fe57b42Smillert 				/* Did they ask us to resolve it ourselves? */
131296a888c6Smillert 				if (resolve != 1) {
1313f0b4d0a9Smillert 					(void)free(spp);
13146fe57b42Smillert 					return(1);
1315f0b4d0a9Smillert 				}
13166fe57b42Smillert 
1317e6aa8bafSmillert 				/* Get partition to disable or ^D */
1318e6aa8bafSmillert 				do {
1319616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
13206fe57b42Smillert 					    'a' + i, 'a' + j);
1321e6aa8bafSmillert 					buf[0] = '\0';
1322616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
1323616cd1c4Smillert 						putchar('\n');
1324e6aa8bafSmillert 						return(1);	/* ^D */
1325616cd1c4Smillert 					}
1326e6aa8bafSmillert 					c = buf[0] - 'a';
1327e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
1328e6aa8bafSmillert 				    c != i && c != j);
1329e6aa8bafSmillert 
1330e6aa8bafSmillert 				/* Mark the selected one as unused */
13316fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
13326fe57b42Smillert 				*freep += lp->d_partitions[c].p_size;
1333e6aa8bafSmillert 				(void)free(spp);
1334e6aa8bafSmillert 				return(has_overlap(lp, freep, resolve));
13356fe57b42Smillert 			}
13366fe57b42Smillert 		}
13376fe57b42Smillert 	}
1338f0b4d0a9Smillert 
1339f0b4d0a9Smillert 	(void)free(spp);
1340e6aa8bafSmillert 	return(0);
13416fe57b42Smillert }
13426fe57b42Smillert 
13436fe57b42Smillert void
13446fe57b42Smillert edit_parms(lp, freep)
13456fe57b42Smillert 	struct disklabel *lp;
13466fe57b42Smillert 	u_int32_t *freep;
13476fe57b42Smillert {
13486fe57b42Smillert 	char *p;
13496fe57b42Smillert 	u_int32_t ui;
135096a888c6Smillert 	struct disklabel oldlabel = *lp;
13516fe57b42Smillert 
1352ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
13536fe57b42Smillert 
13540f820bbbSmillert 	/* disk type */
13550f820bbbSmillert 	for (;;) {
13560f820bbbSmillert 		p = getstring(lp, "disk type",
135741282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
135841282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
135996a888c6Smillert 		if (p == NULL) {
136096a888c6Smillert 			fputs("Command aborted\n", stderr);
136196a888c6Smillert 			return;
136296a888c6Smillert 		}
136341282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
136441282a2aSmillert 			ui = DTYPE_ESDI;
136541282a2aSmillert 		else
136641282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
136741282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
13680f820bbbSmillert 				;
13690f820bbbSmillert 		if (ui < DKMAXTYPES) {
13700f820bbbSmillert 			break;
13710f820bbbSmillert 		} else {
13720f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
13730f820bbbSmillert 			fputs("Valid types are: ", stdout);
13740f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
13750f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
13760f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
13770f820bbbSmillert 					fputs(", ", stdout);
13780f820bbbSmillert 			}
13790f820bbbSmillert 			putchar('\n');
13800f820bbbSmillert 		}
13810f820bbbSmillert 	}
13820f820bbbSmillert 	lp->d_type = ui;
13830f820bbbSmillert 
13846fe57b42Smillert 	/* pack/label id */
13856fe57b42Smillert 	p = getstring(lp, "label name",
13866fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
13876fe57b42Smillert 	    lp->d_packname);
138896a888c6Smillert 	if (p == NULL) {
138996a888c6Smillert 		fputs("Command aborted\n", stderr);
139096a888c6Smillert 		*lp = oldlabel;		/* undo damage */
139196a888c6Smillert 		return;
139296a888c6Smillert 	}
13936fe57b42Smillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1);
13946fe57b42Smillert 	lp->d_packname[sizeof(lp->d_packname) - 1] = '\0';
13956fe57b42Smillert 
13966fe57b42Smillert 	/* sectors/track */
13976fe57b42Smillert 	for (;;) {
13986fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
13996fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
14006fe57b42Smillert 		    lp->d_nsectors, 0);
140196a888c6Smillert 		if (ui == UINT_MAX - 1) {
140296a888c6Smillert 			fputs("Command aborted\n", stderr);
140396a888c6Smillert 			*lp = oldlabel;		/* undo damage */
140496a888c6Smillert 			return;
140596a888c6Smillert 		} if (ui == UINT_MAX)
14066fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14076fe57b42Smillert 		else
14086fe57b42Smillert 			break;
14096fe57b42Smillert 	}
14106fe57b42Smillert 	lp->d_nsectors = ui;
14116fe57b42Smillert 
14126fe57b42Smillert 	/* tracks/cylinder */
14136fe57b42Smillert 	for (;;) {
14146fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
14156fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
14166fe57b42Smillert 		    lp->d_ntracks, 0);
141796a888c6Smillert 		if (ui == UINT_MAX - 1) {
141896a888c6Smillert 			fputs("Command aborted\n", stderr);
141996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
142096a888c6Smillert 			return;
142196a888c6Smillert 		} else if (ui == UINT_MAX)
14226fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14236fe57b42Smillert 		else
14246fe57b42Smillert 			break;
14256fe57b42Smillert 	}
14266fe57b42Smillert 	lp->d_ntracks = ui;
14276fe57b42Smillert 
14286fe57b42Smillert 	/* sectors/cylinder */
1429148b6188Smillert 	for (;;) {
1430148b6188Smillert 		ui = getuint(lp, 0, "sectors/cylinder",
1431148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
1432148b6188Smillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 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)
1438148b6188Smillert 			fputs("Invalid entry\n", stderr);
1439148b6188Smillert 		else
1440148b6188Smillert 			break;
1441148b6188Smillert 	}
1442148b6188Smillert 	lp->d_secpercyl = ui;
14436fe57b42Smillert 
14446fe57b42Smillert 	/* number of cylinders */
14456fe57b42Smillert 	for (;;) {
14466fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
14476fe57b42Smillert 		    "The total number of cylinders on the disk.",
14486fe57b42Smillert 		    lp->d_ncylinders, lp->d_ncylinders, 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)
14546fe57b42Smillert 			fputs("Invalid entry\n", stderr);
14556fe57b42Smillert 		else
14566fe57b42Smillert 			break;
14576fe57b42Smillert 	}
14586fe57b42Smillert 	lp->d_ncylinders = ui;
14596fe57b42Smillert 
14606fe57b42Smillert 	/* total sectors */
14616fe57b42Smillert 	for (;;) {
14626fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
14636fe57b42Smillert 		    "The total number of sectors on the disk.",
14646fe57b42Smillert 		    lp->d_secperunit ? lp->d_secperunit :
14656fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders,
14666fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders, 0);
146796a888c6Smillert 		if (ui == UINT_MAX - 1) {
146896a888c6Smillert 			fputs("Command aborted\n", stderr);
146996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
147096a888c6Smillert 			return;
147196a888c6Smillert 		} else if (ui == UINT_MAX)
14726fe57b42Smillert 			fputs("Invalid entry\n", stderr);
147396a888c6Smillert 		else if (ui > lp->d_secperunit &&
147496a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14756fe57b42Smillert 			/* grow free count */
14766fe57b42Smillert 			*freep += ui - lp->d_secperunit;
1477f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1478f98aebd4Smillert 			    "partition.");
14796fe57b42Smillert 			break;
148096a888c6Smillert 		} else if (ui < lp->d_secperunit &&
148196a888c6Smillert 		    ending_sector == lp->d_secperunit) {
14826fe57b42Smillert 			/* shrink free count */
14836fe57b42Smillert 			if (lp->d_secperunit - ui > *freep)
14846fe57b42Smillert 				fprintf(stderr,
14856fe57b42Smillert 				    "Not enough free space to shrink by %u "
14866fe57b42Smillert 				    "sectors (only %u sectors left)\n",
14876fe57b42Smillert 				    lp->d_secperunit - ui, *freep);
14886fe57b42Smillert 			else {
14896fe57b42Smillert 				*freep -= lp->d_secperunit - ui;
14906fe57b42Smillert 				break;
14916fe57b42Smillert 			}
14926fe57b42Smillert 		} else
14936fe57b42Smillert 			break;
14946fe57b42Smillert 	}
149596a888c6Smillert 	/* Adjust ending_sector if necesary. */
149696a888c6Smillert 	if (ending_sector > ui)
149796a888c6Smillert 		ending_sector = ui;
14986fe57b42Smillert 	lp->d_secperunit = ui;
14996fe57b42Smillert 
15006fe57b42Smillert 	/* rpm */
15016fe57b42Smillert 	for (;;) {
15026fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1503a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
15046fe57b42Smillert 		  lp->d_rpm, lp->d_rpm, 0);
150596a888c6Smillert 		if (ui == UINT_MAX - 1) {
150696a888c6Smillert 			fputs("Command aborted\n", stderr);
150796a888c6Smillert 			*lp = oldlabel;		/* undo damage */
150896a888c6Smillert 			return;
150996a888c6Smillert 		} else if (ui == UINT_MAX)
15106fe57b42Smillert 			fputs("Invalid entry\n", stderr);
15116fe57b42Smillert 		else
15126fe57b42Smillert 			break;
15136fe57b42Smillert 	}
15146fe57b42Smillert 	lp->d_rpm = ui;
1515440b1d70Smillert 
1516440b1d70Smillert 	/* interleave */
1517440b1d70Smillert 	for (;;) {
1518440b1d70Smillert 		ui = getuint(lp, 0, "interleave",
1519440b1d70Smillert 		  "The physical sector interleave, set when formatting.  Almost always 1.",
1520440b1d70Smillert 		  lp->d_interleave, lp->d_interleave, 0);
1521440b1d70Smillert 		if (ui == UINT_MAX - 1) {
1522440b1d70Smillert 			fputs("Command aborted\n", stderr);
1523440b1d70Smillert 			*lp = oldlabel;		/* undo damage */
1524440b1d70Smillert 			return;
1525440b1d70Smillert 		} else if (ui == UINT_MAX || ui == 0)
1526440b1d70Smillert 			fputs("Invalid entry\n", stderr);
1527440b1d70Smillert 		else
1528440b1d70Smillert 			break;
1529440b1d70Smillert 	}
1530440b1d70Smillert 	lp->d_interleave = 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
1581803ff7d5Smillert getdisktype(lp, banner, dev)
15820f820bbbSmillert 	struct disklabel *lp;
15830f820bbbSmillert 	char *banner;
1584803ff7d5Smillert 	char *dev;
15850f820bbbSmillert {
15860f820bbbSmillert 	int i;
1587803ff7d5Smillert 	char *s, *def = "SCSI";
1588803ff7d5Smillert 	struct dtypes {
1589803ff7d5Smillert 		char *dev;
1590803ff7d5Smillert 		char *type;
1591803ff7d5Smillert 	} dtypes[] = {
1592803ff7d5Smillert 		"sd",	"SCSI",
1593803ff7d5Smillert 		"wd",	"IDE",
1594803ff7d5Smillert 		"fd",	"FLOPPY",
1595803ff7d5Smillert 		"xd",	"SMD",
1596803ff7d5Smillert 		"xy",	"SMD",
1597803ff7d5Smillert 		"hd",	"HP-IB",
1598803ff7d5Smillert 		"ccd",	"CCD",
1599803ff7d5Smillert 		"vnd",	"VND",
1600803ff7d5Smillert 		"svnd",	"VND",
1601803ff7d5Smillert 		NULL,	NULL
1602803ff7d5Smillert 	};
1603803ff7d5Smillert 
1604803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1605803ff7d5Smillert 		if (*s == 'r')
1606803ff7d5Smillert 			s++;
1607803ff7d5Smillert 		i = strcspn(s, "0123456789");
1608803ff7d5Smillert 		s[i] = '\0';
1609803ff7d5Smillert 		dev = s;
1610803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1611803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1612803ff7d5Smillert 				def = dtypes[i].type;
1613803ff7d5Smillert 				break;
1614803ff7d5Smillert 			}
1615803ff7d5Smillert 		}
1616803ff7d5Smillert 	}
16170f820bbbSmillert 
16180f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
16190f820bbbSmillert 		puts(banner);
16200f820bbbSmillert 		puts("Possible values are:");
1621eb5dd924Sderaadt 		printf("\"IDE\", ");
16220f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
16230f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
16240f820bbbSmillert 			if (i < DKMAXTYPES - 1)
16250f820bbbSmillert 				fputs(", ", stdout);
16260f820bbbSmillert 		}
16270f820bbbSmillert 		putchar('\n');
16280f820bbbSmillert 
16290f820bbbSmillert 		for (;;) {
16300f820bbbSmillert 			s = getstring(lp, "Disk type",
1631803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1632803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
163396a888c6Smillert 			if (s == NULL)
163496a888c6Smillert 				continue;
16355b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
16365b412421Smillert 				lp->d_type = DTYPE_ESDI;
16375b412421Smillert 				putchar('\n');
16385b412421Smillert 				return;
16395b412421Smillert 			}
16400f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
16410f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
16420f820bbbSmillert 					lp->d_type = i;
16430f820bbbSmillert 					putchar('\n');
16440f820bbbSmillert 					return;
16450f820bbbSmillert 				}
16460f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
16470f820bbbSmillert 			fputs("Valid types are: ", stdout);
16480f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
16490f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
16500f820bbbSmillert 				if (i < DKMAXTYPES - 1)
16510f820bbbSmillert 					fputs(", ", stdout);
16520f820bbbSmillert 			}
16530f820bbbSmillert 			putchar('\n');
16540f820bbbSmillert 		}
16550f820bbbSmillert 	}
16560f820bbbSmillert }
165796a888c6Smillert 
165896a888c6Smillert /*
165996a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
166096a888c6Smillert  * from the user.
16614793b14cSmillert  * XXX - should mention MBR values if DOSLABEL
166296a888c6Smillert  */
166396a888c6Smillert void
1664e8e8bdb7Sart set_bounds(lp, freep)
166596a888c6Smillert 	struct disklabel *lp;
1666e8e8bdb7Sart 	u_int32_t *freep;
166796a888c6Smillert {
166896a888c6Smillert 	u_int32_t ui, start_temp;
166996a888c6Smillert 
167096a888c6Smillert 	/* Starting sector */
167196a888c6Smillert 	do {
167296a888c6Smillert 		ui = getuint(lp, 0, "Starting sector",
167396a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
167496a888c6Smillert 		  starting_sector, lp->d_secperunit, 0);
167596a888c6Smillert 		if (ui == UINT_MAX - 1) {
167696a888c6Smillert 			fputs("Command aborted\n", stderr);
167796a888c6Smillert 			return;
167896a888c6Smillert 		}
167996a888c6Smillert 	} while (ui >= lp->d_secperunit);
168096a888c6Smillert 	start_temp = ui;
168196a888c6Smillert 
16824793b14cSmillert 	/* Size */
168396a888c6Smillert 	do {
1684f98aebd4Smillert 		ui = getuint(lp, 0, "Size ('*' for entire disk)",
1685f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1686f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
1687f98aebd4Smillert 		  lp->d_secperunit - start_temp, 0);
168896a888c6Smillert 		if (ui == UINT_MAX - 1) {
168996a888c6Smillert 			fputs("Command aborted\n", stderr);
169096a888c6Smillert 			return;
169196a888c6Smillert 		}
1692f98aebd4Smillert 	} while (ui > lp->d_secperunit - start_temp);
16934793b14cSmillert 	ending_sector = start_temp + ui;
169496a888c6Smillert 	starting_sector = start_temp;
1695e8e8bdb7Sart 
1696e8e8bdb7Sart 	/* Recalculate the free sectors */
1697c0bdc608Smillert 	editor_countfree(lp, freep);
169896a888c6Smillert }
169996a888c6Smillert 
170096a888c6Smillert /*
170196a888c6Smillert  * Return a list of the "chunks" of free space available
170296a888c6Smillert  */
170396a888c6Smillert struct diskchunk *
170496a888c6Smillert free_chunks(lp)
170596a888c6Smillert 	struct disklabel *lp;
170696a888c6Smillert {
170796a888c6Smillert 	u_int16_t npartitions;
170896a888c6Smillert 	struct partition **spp;
170996a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
171096a888c6Smillert 	int i, numchunks;
171196a888c6Smillert 
171296a888c6Smillert 	/* Sort the partitions based on offset */
171396a888c6Smillert 	spp = sort_partitions(lp, &npartitions);
171496a888c6Smillert 
171596a888c6Smillert 	/* If there are no partitions, it's all free. */
171696a888c6Smillert 	if (spp == NULL) {
171796a888c6Smillert 		chunks[0].start = 0;
171896a888c6Smillert 		chunks[0].stop = ending_sector;
171996a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
172096a888c6Smillert 		return(chunks);
172196a888c6Smillert 	}
172296a888c6Smillert 
172396a888c6Smillert 	/* Find chunks of free space */
172496a888c6Smillert 	numchunks = 0;
172596a888c6Smillert 	if (spp && spp[0]->p_offset > 0) {
172696a888c6Smillert 		chunks[0].start = 0;
172796a888c6Smillert 		chunks[0].stop = spp[0]->p_offset;
172896a888c6Smillert 		numchunks++;
172996a888c6Smillert 	}
173096a888c6Smillert 	for (i = 0; i < npartitions; i++) {
173196a888c6Smillert 		if (i + 1 < npartitions) {
173296a888c6Smillert 			if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) {
173396a888c6Smillert 				chunks[numchunks].start =
173496a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
173596a888c6Smillert 				chunks[numchunks].stop = spp[i+1]->p_offset;
173696a888c6Smillert 				numchunks++;
173796a888c6Smillert 			}
173896a888c6Smillert 		} else {
173996a888c6Smillert 			/* Last partition */
174065ce672dScsapuntz 			if (spp[i]->p_offset + spp[i]->p_size < ending_sector) {
174196a888c6Smillert 
174296a888c6Smillert 				chunks[numchunks].start =
174396a888c6Smillert 				    spp[i]->p_offset + spp[i]->p_size;
174465ce672dScsapuntz 				chunks[numchunks].stop = ending_sector;
174596a888c6Smillert 				numchunks++;
174696a888c6Smillert 			}
174796a888c6Smillert 		}
174896a888c6Smillert 	}
174996a888c6Smillert 
175096a888c6Smillert 	/* Terminate and return */
175196a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
175296a888c6Smillert 	(void)free(spp);
175396a888c6Smillert 	return(chunks);
175496a888c6Smillert }
17554793b14cSmillert 
17564793b14cSmillert /*
17574793b14cSmillert  * What is the OpenBSD portion of the disk?  Uses the MBR if applicable.
17584793b14cSmillert  */
17594793b14cSmillert void
17604793b14cSmillert find_bounds(lp)
17614793b14cSmillert 	struct disklabel *lp;
17624793b14cSmillert {
1763f98aebd4Smillert 	struct  partition *pp = &lp->d_partitions[2];
17644793b14cSmillert 
17654793b14cSmillert 	/* Defaults */
17664793b14cSmillert 	/* XXX - reserve a cylinder for hp300? */
17674793b14cSmillert 	starting_sector = 0;
17684793b14cSmillert 	ending_sector = lp->d_secperunit;
17694793b14cSmillert 
17704793b14cSmillert #ifdef DOSLABEL
1771aaa7b57dSderaadt 	/* If we have an MBR, use values from the OpenBSD/FreeBSD parition. */
1772aaa7b57dSderaadt 	if (dosdp && pp->p_size &&
1773aaa7b57dSderaadt 	    (dosdp->dp_typ == DOSPTYP_OPENBSD ||
1774aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_FREEBSD ||
1775aaa7b57dSderaadt 	    dosdp->dp_typ == DOSPTYP_NETBSD)) {
17764793b14cSmillert 		starting_sector = get_le(&dosdp->dp_start);
17774793b14cSmillert 		ending_sector = starting_sector + get_le(&dosdp->dp_size);
17784793b14cSmillert 		printf("Treating sectors %u-%u as the OpenBSD portion of the "
17794793b14cSmillert 		    "disk.\nYou can use the 'b' command to change this.\n",
17804793b14cSmillert 		    starting_sector, ending_sector);
1781f98aebd4Smillert 		/*
1782f98aebd4Smillert 		 * XXX - check to see if any BSD/SWAP partitions go beyond
1783f98aebd4Smillert 		 *	 ending_sector and prompt to extend ending_sector if so.
1784f98aebd4Smillert 		 */
17854793b14cSmillert 	}
17864793b14cSmillert #endif
17874793b14cSmillert }
1788c0bdc608Smillert 
1789c0bdc608Smillert /*
1790c0bdc608Smillert  * Calculate free space.
1791c0bdc608Smillert  */
1792c0bdc608Smillert void
1793c0bdc608Smillert editor_countfree(lp, freep)
1794c0bdc608Smillert 	struct disklabel *lp;
1795c0bdc608Smillert 	u_int32_t *freep;
1796c0bdc608Smillert {
1797c0bdc608Smillert 	struct partition *pp;
1798c0bdc608Smillert 	int i;
1799c0bdc608Smillert 
1800c0bdc608Smillert 	*freep = ending_sector - starting_sector;
1801c0bdc608Smillert 	for (i = 0; i < lp->d_npartitions; i++) {
1802c0bdc608Smillert 		    pp = &lp->d_partitions[i];
1803c0bdc608Smillert 		    if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
1804c0bdc608Smillert 			pp->p_size > 0 &&
1805c0bdc608Smillert 			pp->p_offset + pp->p_size <= ending_sector &&
1806c0bdc608Smillert 			pp->p_offset >= starting_sector)
1807c0bdc608Smillert 			*freep -= pp->p_size;
1808c0bdc608Smillert 	}
1809c0bdc608Smillert }
1810*617e6e4aSmillert 
1811*617e6e4aSmillert void
1812*617e6e4aSmillert editor_help(arg)
1813*617e6e4aSmillert 	char *arg;
1814*617e6e4aSmillert {
1815*617e6e4aSmillert 
1816*617e6e4aSmillert 	/* XXX - put these strings in a table instead? */
1817*617e6e4aSmillert 	switch (*arg) {
1818*617e6e4aSmillert 	case 'p':
1819*617e6e4aSmillert 		puts(
1820*617e6e4aSmillert "The 'p' command prints the current disk label.  By default, it prints the\n"
1821*617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1822*617e6e4aSmillert "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1823*617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1824*617e6e4aSmillert 		break;
1825*617e6e4aSmillert 	case 'M':
1826*617e6e4aSmillert 		puts(
1827*617e6e4aSmillert "The 'M' command pipes the entire OpenBSD manual page for disklabel though\n"
1828*617e6e4aSmillert "The 'less' pager.  It is especially useful during install when the normal\n"
1829*617e6e4aSmillert "system manual is not available.\n");
1830*617e6e4aSmillert 		break;
1831*617e6e4aSmillert 	case 'e':
1832*617e6e4aSmillert 		puts(
1833*617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters.  These include\n"
1834*617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n"
1835*617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n"
1836*617e6e4aSmillert "type, and a descriptive label string.  You should not change these unless\n"
1837*617e6e4aSmillert "you know what you are doing\n");
1838*617e6e4aSmillert 		break;
1839*617e6e4aSmillert 	case 'a':
1840*617e6e4aSmillert 		puts(
1841*617e6e4aSmillert "The 'a' command adds new partitions to the disk.  It takes as an optional\n"
1842*617e6e4aSmillert "argument the partition letter to add.  If you do not specify a partition\n"
1843*617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n"
1844*617e6e4aSmillert "default answer\n");
1845*617e6e4aSmillert 		break;
1846*617e6e4aSmillert 	case 'b':
1847*617e6e4aSmillert 		puts(
1848*617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n"
1849*617e6e4aSmillert "the disk.  This is only useful on disks with an fdisk partition.  By default,\n"
1850*617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n"
1851*617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition.  You should only change\n"
1852*617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n"
1853*617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be.  You\n"
1854*617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n"
1855*617e6e4aSmillert "(minus the starting sector).  Use this option with care; if you extend the\n"
1856*617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n"
1857*617e6e4aSmillert "corrupt the other operating system's data.\n");
1858*617e6e4aSmillert 		break;
1859*617e6e4aSmillert 	case 'c':
1860*617e6e4aSmillert 		puts(
1861*617e6e4aSmillert "The 'c' command is used to change the size of an existing partition.  It\n"
1862*617e6e4aSmillert "takes as an optional argument the partition letter to change.  If you do not\n"
1863*617e6e4aSmillert "specify a partition letter, you will be prompted for one.  You may add a '+'\n"
1864*617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n"
1865*617e6e4aSmillert "instead of entering an absolute value.  You may also use a suffix to indicate\n"
1866*617e6e4aSmillert "the units the values is in terms of.  Possible suffixes are 'b' for bytes,\n"
1867*617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n"
1868*617e6e4aSmillert "no suffix for sectors (usually 512 bytes).  You may also enter '*' to change\n"
1869*617e6e4aSmillert "the size to be the total number of free sectors remaining.\n");
1870*617e6e4aSmillert 		break;
1871*617e6e4aSmillert 	case 'd':
1872*617e6e4aSmillert 		puts(
1873*617e6e4aSmillert "The 'd' command is used to delete an existing partition.  It takes as an\n"
1874*617e6e4aSmillert "optional argument the partition letter to change.  If you do not specify a\n"
1875*617e6e4aSmillert "partition letter, you will be prompted for one.  You may not delete the ``c''\n"
1876*617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n"
1877*617e6e4aSmillert "it does not take up any space).\n");
1878*617e6e4aSmillert 		break;
1879*617e6e4aSmillert 	case 'm':
1880*617e6e4aSmillert 		puts(
1881*617e6e4aSmillert "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"
1882*617e6e4aSmillert "partition letter, you will be prompted for one.  This option allows the user\n"
1883*617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n"
1884*617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n"
1885*617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n");
1886*617e6e4aSmillert 		break;
1887*617e6e4aSmillert 	case 'r':
1888*617e6e4aSmillert 		puts(
1889*617e6e4aSmillert "The 'r' command is used to recalculate the free space available.  This option\n"
1890*617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n"
1891*617e6e4aSmillert "disklabel gets confused.\n");
1892*617e6e4aSmillert 		break;
1893*617e6e4aSmillert 	case 'u':
1894*617e6e4aSmillert 		puts(
1895*617e6e4aSmillert "The 'u' command will undo (or redo) the last change.  Entering 'u' once will\n"
1896*617e6e4aSmillert "undo your last change.  Entering it again will restore the change.\n");
1897*617e6e4aSmillert 		break;
1898*617e6e4aSmillert 	case 's':
1899*617e6e4aSmillert 		puts(
1900*617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n"
1901*617e6e4aSmillert "(suitable for loading via disklabel's [-R] option).  It takes as an optional\n"
1902*617e6e4aSmillert "argument the filename to save the label to.  If you do not specify a filename,\n"
1903*617e6e4aSmillert "you will be prompted for one.\n");
1904*617e6e4aSmillert 		break;
1905*617e6e4aSmillert 	case 'w':
1906*617e6e4aSmillert 		puts(
1907*617e6e4aSmillert "The 'w' command will write the current label to disk.  This option will\n"
1908*617e6e4aSmillert "commit any changes to the on-disk label.\n");
1909*617e6e4aSmillert 		break;
1910*617e6e4aSmillert 	case 'q':
1911*617e6e4aSmillert 		puts(
1912*617e6e4aSmillert "The 'q' command quits the label editor.  If any changes have been made you\n"
1913*617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n");
1914*617e6e4aSmillert 		break;
1915*617e6e4aSmillert 	case 'x':
1916*617e6e4aSmillert 		puts(
1917*617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n"
1918*617e6e4aSmillert "on-disk label.\n");
1919*617e6e4aSmillert 		break;
1920*617e6e4aSmillert 	default:
1921*617e6e4aSmillert 		puts("Available commands:");
1922*617e6e4aSmillert 		puts("\tp [unit]  - print label.");
1923*617e6e4aSmillert 		puts("\tM         - show entire OpenBSD man page for disklabel.");
1924*617e6e4aSmillert 		puts("\te         - edit drive parameters.");
1925*617e6e4aSmillert 		puts("\ta [part]  - add new partition.");
1926*617e6e4aSmillert 		puts("\tb         - set OpenBSD disk boundaries.");
1927*617e6e4aSmillert 		puts("\tc [part]  - change partition size.");
1928*617e6e4aSmillert 		puts("\td [part]  - delete partition.");
1929*617e6e4aSmillert 		puts("\tm [part]  - modify existing partition.");
1930*617e6e4aSmillert 		puts("\tr         - recalculate free space.");
1931*617e6e4aSmillert 		puts("\tu         - undo last change.");
1932*617e6e4aSmillert 		puts("\ts [path]  - save label to file.");
1933*617e6e4aSmillert 		puts("\tw         - write label to disk.");
1934*617e6e4aSmillert 		puts("\tq         - quit and save changes.");
1935*617e6e4aSmillert 		puts("\tx         - exit without saving changes.");
1936*617e6e4aSmillert 		puts("\t? [cmnd]  - this message or command specific help.");
1937*617e6e4aSmillert 		puts(
1938*617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t"
1939*617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t"
1940*617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t"
1941*617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n"
1942*617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help.");
1943*617e6e4aSmillert 		break;
1944*617e6e4aSmillert 	}
1945*617e6e4aSmillert }
1946