xref: /openbsd/sbin/disklabel/editor.c (revision ea37abd3)
1*ea37abd3Sderaadt /*	$OpenBSD: editor.c,v 1.16 1997/10/17 04:37:52 deraadt Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
46fe57b42Smillert  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  * All rights reserved.
66fe57b42Smillert  *
76fe57b42Smillert  * Redistribution and use in source and binary forms, with or without
86fe57b42Smillert  * modification, are permitted provided that the following conditions
96fe57b42Smillert  * are met:
106fe57b42Smillert  * 1. Redistributions of source code must retain the above copyright
116fe57b42Smillert  *    notice, this list of conditions and the following disclaimer.
126fe57b42Smillert  * 2. Redistributions in binary form must reproduce the above copyright
136fe57b42Smillert  *    notice, this list of conditions and the following disclaimer in the
146fe57b42Smillert  *    documentation and/or other materials provided with the distribution.
156fe57b42Smillert  * 3. All advertising materials mentioning features or use of this software
166fe57b42Smillert  *    must display the following acknowledgement:
176fe57b42Smillert  *	This product includes software developed by Todd C. Miller.
186fe57b42Smillert  * 4. The name of the author may not be used to endorse or promote products
196fe57b42Smillert  *    derived from this software without specific prior written permission.
206fe57b42Smillert  *
216fe57b42Smillert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
226fe57b42Smillert  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
236fe57b42Smillert  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
246fe57b42Smillert  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
256fe57b42Smillert  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
266fe57b42Smillert  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
276fe57b42Smillert  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
286fe57b42Smillert  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
296fe57b42Smillert  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
306fe57b42Smillert  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
316fe57b42Smillert  */
326fe57b42Smillert 
336fe57b42Smillert #ifndef lint
34*ea37abd3Sderaadt static char rcsid[] = "$OpenBSD: editor.c,v 1.16 1997/10/17 04:37:52 deraadt Exp $";
356fe57b42Smillert #endif /* not lint */
366fe57b42Smillert 
376fe57b42Smillert #include <sys/types.h>
386fe57b42Smillert #include <sys/param.h>
396fe57b42Smillert #define	DKTYPENAMES
406fe57b42Smillert #include <sys/disklabel.h>
416fe57b42Smillert 
426fe57b42Smillert #include <ufs/ffs/fs.h>
436fe57b42Smillert 
446fe57b42Smillert #include <ctype.h>
456fe57b42Smillert #include <err.h>
466fe57b42Smillert #include <errno.h>
476fe57b42Smillert #include <string.h>
486fe57b42Smillert #include <stdio.h>
496fe57b42Smillert #include <stdlib.h>
506fe57b42Smillert #include <unistd.h>
516fe57b42Smillert 
526fe57b42Smillert /* flags for getuint() */
536fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
546fe57b42Smillert #define	DO_ROUNDING	0x00000002
556fe57b42Smillert 
566fe57b42Smillert void	edit_parms __P((struct disklabel *, u_int32_t *));
576fe57b42Smillert int	editor __P((struct disklabel *, int));
586fe57b42Smillert void	editor_add __P((struct disklabel *, u_int32_t *, char *));
596fe57b42Smillert void	editor_modify __P((struct disklabel *, u_int32_t *, char *));
606fe57b42Smillert void	editor_delete __P((struct disklabel *, u_int32_t *, char *));
616fe57b42Smillert void	editor_display __P((struct disklabel *, u_int32_t *, char));
626fe57b42Smillert void	editor_change __P((struct disklabel *, u_int32_t *, char *));
636fe57b42Smillert char	*getstring __P((struct disklabel *, char *, char *, char *));
646fe57b42Smillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int));
656fe57b42Smillert int	has_overlap __P((struct disklabel *, u_int32_t *, int));
666fe57b42Smillert void	make_contiguous __P((struct disklabel *));
676fe57b42Smillert u_int32_t next_offset __P((struct disklabel *));
686fe57b42Smillert int	partition_cmp __P((const void *, const void *));
69a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));
700f820bbbSmillert void	getdisktype __P((struct disklabel *, char *));
716fe57b42Smillert 
726fe57b42Smillert /* from disklabel.c */
736fe57b42Smillert int	checklabel __P((struct disklabel *));
746fe57b42Smillert void	display __P((FILE *, struct disklabel *));
756fe57b42Smillert void	display_partition __P((FILE *, struct disklabel *, int, char));
766fe57b42Smillert struct disklabel *readlabel __P((int));
776fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int));
786fe57b42Smillert int	writelabel __P((int, char *, struct disklabel *));
796fe57b42Smillert extern	char *bootarea, *specname;
8069220492Smillert extern	int donothing;
816fe57b42Smillert 
826fe57b42Smillert /*
836fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
846fe57b42Smillert  */
856fe57b42Smillert int
866fe57b42Smillert editor(lp, f)
876fe57b42Smillert 	struct disklabel *lp;
886fe57b42Smillert 	int f;
896fe57b42Smillert {
906fe57b42Smillert 	struct disklabel lastlabel, tmplabel, label = *lp;
916fe57b42Smillert 	u_int32_t freeblocks;
926fe57b42Smillert 	FILE *fp;
936fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
946fe57b42Smillert 	int i;
956fe57b42Smillert 
966fe57b42Smillert 	/* Set freeblocks based on initial label */
976fe57b42Smillert 	freeblocks = label.d_secperunit;
986fe57b42Smillert 	for (i = 0; i < label.d_npartitions; i++)
996fe57b42Smillert 		if (label.d_partitions[i].p_fstype != FS_UNUSED &&
100229f463eSmillert 		    label.d_partitions[i].p_fstype != FS_BOOT &&
1016fe57b42Smillert 		    label.d_partitions[i].p_size > 0)
1026fe57b42Smillert 			freeblocks -= label.d_partitions[i].p_size;
1036fe57b42Smillert 
104*ea37abd3Sderaadt 	puts("Initial label editor (enter '?' for help at any prompt)");
1056fe57b42Smillert 	if (has_overlap(&label, &freeblocks, 1))
1066fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1076fe57b42Smillert 
1080f820bbbSmillert 	getdisktype(&label, "You need to specify a disk type for this disk.");
1090f820bbbSmillert 
1106fe57b42Smillert #ifdef CYLCHECK
1116fe57b42Smillert 	puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically.");
1126fe57b42Smillert #endif
1136fe57b42Smillert 
1146fe57b42Smillert 	lastlabel = label;
1156fe57b42Smillert 	for (;;) {
1166fe57b42Smillert 		fputs("> ", stdout);
1176fe57b42Smillert 		fflush(stdout);
1186fe57b42Smillert 		rewind(stdin);
1196e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1206e0becc5Smillert 			putchar('\n');
1216e0becc5Smillert 			buf[0] = 'q';
1226e0becc5Smillert 			buf[1] = '\0';
1236e0becc5Smillert 		}
124260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
125260513deSmillert 			continue;
126260513deSmillert 		arg = strtok(NULL, " \t\r\n");
1276fe57b42Smillert 
1286fe57b42Smillert 		switch (*cmd) {
1296fe57b42Smillert 
1306fe57b42Smillert 		case '?':
131*ea37abd3Sderaadt 		case 'h':
132*ea37abd3Sderaadt 			puts("Available commands:");
133*ea37abd3Sderaadt 			puts("\tp [unit]   - print label.");
1349bb06b6bSderaadt 			puts("\tM          - show entire OpenBSD man page for disklabel.");
1356fe57b42Smillert 			puts("\te          - edit drive parameters.");
1366fe57b42Smillert 			puts("\ta [part]   - add new partition.");
1376fe57b42Smillert 			puts("\tc [part]   - change partition size.");
1386fe57b42Smillert 			puts("\td [part]   - delete partition.");
1396fe57b42Smillert 			puts("\tm [part]   - modify existing partition.");
1406fe57b42Smillert 			puts("\tu          - undo last change.");
1416fe57b42Smillert 			puts("\ts [path]   - save label to file.");
142040947cfSmillert 			puts("\tw          - write label to disk.");
1436fe57b42Smillert 			puts("\tq          - quit and save changes.");
1446fe57b42Smillert 			puts("\tx          - exit without saving changes.");
145*ea37abd3Sderaadt 			puts("\t?          - this message.");
146*ea37abd3Sderaadt 			puts("Numeric parameters may use suffixes to indicate units:\n\t'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t'g' for gigabytes or no suffix for blocks (usually 512 bytes).\n\tNon-block units will be rounded to the nearest cylinder.");
1476fe57b42Smillert 			break;
1486fe57b42Smillert 
1496fe57b42Smillert 		case 'a':
1506fe57b42Smillert 			tmplabel = lastlabel;
1516fe57b42Smillert 			lastlabel = label;
1526fe57b42Smillert 			editor_add(&label, &freeblocks, arg);
1536fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
1546fe57b42Smillert 				lastlabel = tmplabel;
1556fe57b42Smillert 			break;
1566fe57b42Smillert 
1576fe57b42Smillert 		case 'c':
1586fe57b42Smillert 			tmplabel = lastlabel;
1596fe57b42Smillert 			lastlabel = label;
1606fe57b42Smillert 			editor_change(&label, &freeblocks, arg);
1616fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
1626fe57b42Smillert 				lastlabel = tmplabel;
1636fe57b42Smillert 			break;
1646fe57b42Smillert 
1656fe57b42Smillert 		case 'd':
1666fe57b42Smillert 			tmplabel = lastlabel;
1676fe57b42Smillert 			lastlabel = label;
1686fe57b42Smillert 			editor_delete(&label, &freeblocks, arg);
1696fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
1706fe57b42Smillert 				lastlabel = tmplabel;
1716fe57b42Smillert 			break;
1726fe57b42Smillert 
1736fe57b42Smillert 		case 'm':
1746fe57b42Smillert 			tmplabel = lastlabel;
1756fe57b42Smillert 			lastlabel = label;
1766fe57b42Smillert 			editor_modify(&label, &freeblocks, arg);
1776fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
1786fe57b42Smillert 				lastlabel = tmplabel;
1796fe57b42Smillert 			break;
1806fe57b42Smillert 
1816fe57b42Smillert 		case 'p':
1826fe57b42Smillert 			editor_display(&label, &freeblocks, arg ? *arg : 0);
1836fe57b42Smillert 			break;
1846fe57b42Smillert 
1855d12b01bSderaadt 		case 'M':
1865d12b01bSderaadt 			fp = popen("/usr/bin/less", "w");
1875d12b01bSderaadt 			if (fp) {
1885d12b01bSderaadt 				extern char manpage[];
1895d12b01bSderaadt 
1905d12b01bSderaadt 				(void) fwrite(manpage, strlen(manpage), 1, fp);
1915d12b01bSderaadt 				pclose(fp);
1925d12b01bSderaadt 			}
1935d12b01bSderaadt 			break;
1945d12b01bSderaadt 
1956fe57b42Smillert 		case 'q':
19669220492Smillert 			if (donothing) {
19769220492Smillert 				puts("In no change mode, not writing label.");
19869220492Smillert 				return(1);
19969220492Smillert 			}
2006fe57b42Smillert 			if (memcmp(lp, &label, sizeof(label)) == 0) {
2016fe57b42Smillert 				puts("No changes.");
2026fe57b42Smillert 				return(1);
2036fe57b42Smillert 			}
2046fe57b42Smillert 			do {
2056fe57b42Smillert 				arg = getstring(lp, "Save changes?",
2066fe57b42Smillert 				    "Save changes you have made to the label?",
2076fe57b42Smillert 				    "n");
2086fe57b42Smillert 			} while (tolower(*arg) != 'y' && tolower(*arg) != 'n');
2096fe57b42Smillert 			if (tolower(*arg) == 'y') {
2106fe57b42Smillert 				*lp = label;
2116fe57b42Smillert 				if (writelabel(f, bootarea, lp) == 0)
2126fe57b42Smillert 					return(0);
2136fe57b42Smillert 			}
2146fe57b42Smillert 			return(1);
2156fe57b42Smillert 			/* NOTREACHED */
2166fe57b42Smillert 			break;
2176fe57b42Smillert 
2186fe57b42Smillert 		case 's':
2196fe57b42Smillert 			if (arg == NULL) {
220260513deSmillert 				arg = getstring(lp, "Filename",
2216fe57b42Smillert 				    "Name of the file to save label into.",
2226fe57b42Smillert 				    NULL);
2236fe57b42Smillert 				if (*arg == '\0')
2246fe57b42Smillert 					break;
2256fe57b42Smillert 			}
2266fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
2276fe57b42Smillert 				warn("cannot open %s", arg);
2286fe57b42Smillert 			} else {
2296fe57b42Smillert 				display(fp, &label);
2306fe57b42Smillert 				(void)fclose(fp);
2316fe57b42Smillert 			}
2326fe57b42Smillert 			break;
2336fe57b42Smillert 
2346fe57b42Smillert 		case 'u':
2356fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0) {
2366fe57b42Smillert 				puts("Nothing to undo!");
2376fe57b42Smillert 			} else {
2386fe57b42Smillert 				tmplabel = label;
2396fe57b42Smillert 				label = lastlabel;
2406fe57b42Smillert 				lastlabel = tmplabel;
2416fe57b42Smillert 				puts("Last change undone.");
2426fe57b42Smillert 			}
2436fe57b42Smillert 			break;
2446fe57b42Smillert 
245040947cfSmillert 		case 'w':
246040947cfSmillert 			if (donothing)
247040947cfSmillert 				puts("In no change mode, not writing label.");
248040947cfSmillert 			else if (memcmp(lp, &label, sizeof(label)) == 0)
249040947cfSmillert 				puts("No changes.");
250040947cfSmillert 			else if (writelabel(f, bootarea, &label) != 0)
251040947cfSmillert 				warnx("unable to write label");
2525af08e9cSmillert 			else
2535af08e9cSmillert 				*lp = label;
254040947cfSmillert 			break;
255040947cfSmillert 
2566fe57b42Smillert 		case 'x':
2576fe57b42Smillert 			return(1);
2586fe57b42Smillert 			break;
2596fe57b42Smillert 
2606fe57b42Smillert 		case '\n':
2616fe57b42Smillert 			break;
2626fe57b42Smillert 
2636fe57b42Smillert 		case 'e':
2646fe57b42Smillert 			tmplabel = lastlabel;
2656fe57b42Smillert 			lastlabel = label;
2666fe57b42Smillert 			edit_parms(&label, &freeblocks);
2676fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2686fe57b42Smillert 				lastlabel = tmplabel;
2696fe57b42Smillert 			break;
2706fe57b42Smillert 
2716fe57b42Smillert 		default:
2726fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
2736fe57b42Smillert 			break;
2746fe57b42Smillert 		}
2756fe57b42Smillert 	}
2766fe57b42Smillert }
2776fe57b42Smillert 
2786fe57b42Smillert /*
2796fe57b42Smillert  * Add a new partition.
2806fe57b42Smillert  */
2816fe57b42Smillert void
2826fe57b42Smillert editor_add(lp, freep, p)
2836fe57b42Smillert 	struct disklabel *lp;
2846fe57b42Smillert 	u_int32_t *freep;
2856fe57b42Smillert 	char *p;
2866fe57b42Smillert {
2876fe57b42Smillert 	struct partition origpart, *pp;
2886fe57b42Smillert 	char buf[BUFSIZ];
2896fe57b42Smillert 	int i, partno;
2906fe57b42Smillert 	u_int32_t ui;
2916fe57b42Smillert 
2926fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
2936fe57b42Smillert 	if (*freep == 0) {
2946fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
2956fe57b42Smillert 		    stderr);
2966fe57b42Smillert 		return;
2976fe57b42Smillert 	}
2986fe57b42Smillert 
2996fe57b42Smillert 	/* XXX - make more like other editor_* */
3006fe57b42Smillert 	if (p != NULL) {
3016fe57b42Smillert 		partno = p[0] - 'a';
3026fe57b42Smillert 		if (partno < 0 || partno >= MAXPARTITIONS) {
3036fe57b42Smillert 			fprintf(stderr,
3046fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
3056fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
3066fe57b42Smillert 			return;
3076fe57b42Smillert 		}
3086fe57b42Smillert 	} else {
3096fe57b42Smillert 		/* Find first unused partition that is not 'b' or 'c' */
3106fe57b42Smillert 		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {
3116fe57b42Smillert 			if (lp->d_partitions[partno].p_size == 0 &&
3126fe57b42Smillert 			    partno != 1 && partno != 2)
3136fe57b42Smillert 				break;
3146fe57b42Smillert 		}
3156fe57b42Smillert 		if (partno < MAXPARTITIONS) {
3166fe57b42Smillert 			buf[0] = partno + 'a';
3176fe57b42Smillert 			buf[1] = '\0';
3186fe57b42Smillert 			p = &buf[0];
3196fe57b42Smillert 		} else
3206fe57b42Smillert 			p = NULL;
3216fe57b42Smillert 		for (;;) {
3226fe57b42Smillert 			p = getstring(lp, "partition",
3236fe57b42Smillert 			    "The letter of the new partition, a - p.", p);
3246fe57b42Smillert 			partno = p[0] - 'a';
3256fe57b42Smillert 			if (partno >= 0 && partno < MAXPARTITIONS)
3266fe57b42Smillert 				break;
3276fe57b42Smillert 			fprintf(stderr,
3286fe57b42Smillert 			    "Partition must be between 'a' and '%c'.\n",
3296fe57b42Smillert 			    'a' + MAXPARTITIONS - 1);
3306fe57b42Smillert 		}
3316fe57b42Smillert 	}
3326fe57b42Smillert 	/* Increase d_npartitions and set defaults if necesary */
3336fe57b42Smillert 	pp = &lp->d_partitions[partno];
3346fe57b42Smillert 	if (partno >= lp->d_npartitions || pp->p_fstype == FS_UNUSED) {
3356fe57b42Smillert 		if (partno >= lp->d_npartitions)
3366fe57b42Smillert 			lp->d_npartitions = partno + 1;
3376fe57b42Smillert 		memset(pp, 0, sizeof(*pp));
3386fe57b42Smillert 		pp->p_offset = next_offset(lp);
3396fe57b42Smillert 		pp->p_size = *freep;
340f0b4d0a9Smillert 		if (partno == 1)
341f0b4d0a9Smillert 			pp->p_fstype = FS_SWAP;
342f0b4d0a9Smillert 		else
3436fe57b42Smillert 			pp->p_fstype = FS_BSDFFS;
3446fe57b42Smillert 		pp->p_fsize = 1024;
3456fe57b42Smillert 		pp->p_frag = 8;
3466fe57b42Smillert 		pp->p_cpg = 16;
3476fe57b42Smillert 	}
3486fe57b42Smillert 	origpart = *pp;
3496fe57b42Smillert 
3506fe57b42Smillert 	/* Get fstype */
3516fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
3526fe57b42Smillert 		p = getstring(lp, "FS type",
3536fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
3546fe57b42Smillert 		    fstypenames[pp->p_fstype]);
3556fe57b42Smillert 		for (i = 0; i < FSMAXTYPES; i++) {
3566fe57b42Smillert 			if (!strcasecmp(p, fstypenames[i])) {
3576fe57b42Smillert 				pp->p_fstype = i;
3586fe57b42Smillert 				break;
3596fe57b42Smillert 			}
3606fe57b42Smillert 		}
3616fe57b42Smillert 		if (i >= FSMAXTYPES) {
3626fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
3636fe57b42Smillert 			pp->p_fstype = FS_OTHER;
3646fe57b42Smillert 		}
3656fe57b42Smillert 	} else {
3666fe57b42Smillert 		for (;;) {
3676fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
3686fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
3696fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
3706fe57b42Smillert 			if (ui == UINT_MAX)
3716fe57b42Smillert 				fputs("Invalid entry\n", stderr);
3726fe57b42Smillert 			else
3736fe57b42Smillert 				break;
3746fe57b42Smillert 		}
3756fe57b42Smillert 		pp->p_fstype = ui;
3766fe57b42Smillert 	}
3776fe57b42Smillert 
3786fe57b42Smillert getoff1:
3796fe57b42Smillert 	/* Get offset */
3806fe57b42Smillert 	for (;;) {
3816fe57b42Smillert 		ui = getuint(lp, partno, "offset",
3826fe57b42Smillert 		   "Starting sector for this partition.", pp->p_offset,
3836fe57b42Smillert 		   pp->p_offset, DO_CONVERSIONS |
3846fe57b42Smillert 		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
3856fe57b42Smillert 		if (ui == UINT_MAX)
3866fe57b42Smillert 			fputs("Invalid entry\n", stderr);
3876fe57b42Smillert 		else
3886fe57b42Smillert 			break;
3896fe57b42Smillert 	}
3906fe57b42Smillert 	pp->p_offset = ui;
3916fe57b42Smillert 
3926fe57b42Smillert 	/* Get size */
3936fe57b42Smillert 	for (;;) {
3946fe57b42Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
3956fe57b42Smillert 		    pp->p_size, *freep, DO_CONVERSIONS |
3966fe57b42Smillert 		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
3976fe57b42Smillert 		if (ui + pp->p_offset > lp->d_partitions[2].p_size +
3986fe57b42Smillert 		    lp->d_partitions[2].p_offset)
3996fe57b42Smillert 			fputs("Partition must not extend past 'c'\n", stderr);
4006fe57b42Smillert 		else if (ui > *freep)
4016fe57b42Smillert 			/* XXX - prompt user to steal space from another partition */
4026fe57b42Smillert 			fprintf(stderr,"Sorry, there are only %u blocks left\n",
4036fe57b42Smillert 			    *freep);
4046fe57b42Smillert 		else
4056fe57b42Smillert 			break;
4066fe57b42Smillert 	}
4076fe57b42Smillert 	pp->p_size = ui;
4086fe57b42Smillert 	if (pp->p_size == 0)
4096fe57b42Smillert 		return;
4106fe57b42Smillert 
4116fe57b42Smillert 	/* Check for overlap and restore if not resolved */
4126fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
4136fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
4146fe57b42Smillert 		pp->p_offset = origpart.p_offset;
4156fe57b42Smillert 		pp->p_size = origpart.p_size;
4166fe57b42Smillert 		goto getoff1;		/* Yeah, I know... */
4176fe57b42Smillert 	}
4186fe57b42Smillert 
4196fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
4206fe57b42Smillert 		/* get fsize */
4216fe57b42Smillert 		for (;;) {
4226fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
4236fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
4246fe57b42Smillert 			    pp->p_fsize, pp->p_fsize, 0);
4256fe57b42Smillert 			if (ui == UINT_MAX)
4266fe57b42Smillert 				fputs("Invalid entry\n", stderr);
4276fe57b42Smillert 			else
4286fe57b42Smillert 				break;
4296fe57b42Smillert 		}
4306fe57b42Smillert 		pp->p_fsize = ui;
4316fe57b42Smillert 		if (pp->p_fsize == 0)
4326fe57b42Smillert 			puts("Zero fragment size implies zero block size");
4336fe57b42Smillert 
4346fe57b42Smillert 		/* get bsize */
4356fe57b42Smillert 		/* XXX - do before frag size? */
4366fe57b42Smillert 		for (; pp->p_fsize > 0;) {
4376fe57b42Smillert 			ui = getuint(lp, partno, "block size",
4386fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
4396fe57b42Smillert 			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
4406fe57b42Smillert 			    0);
4416fe57b42Smillert 
4426fe57b42Smillert 			/* sanity checks */
4436fe57b42Smillert 			if (ui == UINT_MAX)
4446fe57b42Smillert 				fputs("Invalid entry\n", stderr);
4456fe57b42Smillert 			else if (ui < getpagesize())
4466fe57b42Smillert 				fprintf(stderr,
4476fe57b42Smillert 				    "Error: block size must be at least as big "
4486fe57b42Smillert 				    "as page size (%d).\n", getpagesize());
4496fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
4506fe57b42Smillert 				fputs("Error: block size must be a multiple of the fragment size.\n", stderr);
4516fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
4526fe57b42Smillert 				fputs("Error: block size must be at least as big as fragment size.\n", stderr);
4536fe57b42Smillert 			else
4546fe57b42Smillert 				break;
4556fe57b42Smillert 		}
4566fe57b42Smillert 		pp->p_frag = ui / pp->p_fsize;
4576fe57b42Smillert 
4586fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
4596fe57b42Smillert 			/* get cpg */
4606fe57b42Smillert 			for (;;) {
4616fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
4626fe57b42Smillert 				    "Number of filesystem cylinders per group.  Usually 16 or 8.",
4636fe57b42Smillert 				    pp->p_cpg, pp->p_cpg, 0);
4646fe57b42Smillert 				if (ui == UINT_MAX)
4656fe57b42Smillert 					fputs("Invalid entry\n", stderr);
4666fe57b42Smillert 				else
4676fe57b42Smillert 					break;
4686fe57b42Smillert 			}
4696fe57b42Smillert 			pp->p_cpg = ui;
4706fe57b42Smillert 		}
4716fe57b42Smillert 	}
4726fe57b42Smillert 	/* Update free block count and make sure things stay contiguous. */
4736fe57b42Smillert 	*freep -= pp->p_size;
4746fe57b42Smillert 	make_contiguous(lp);
4756fe57b42Smillert }
4766fe57b42Smillert 
4776fe57b42Smillert /*
4786fe57b42Smillert  * Change an existing partition.
4796fe57b42Smillert  */
4806fe57b42Smillert void
4816fe57b42Smillert editor_modify(lp, freep, p)
4826fe57b42Smillert 	struct disklabel *lp;
4836fe57b42Smillert 	u_int32_t *freep;
4846fe57b42Smillert 	char *p;
4856fe57b42Smillert {
4866fe57b42Smillert 	struct partition origpart, *pp;
4876fe57b42Smillert 	u_int32_t ui;
4886fe57b42Smillert 	int partno;
4896fe57b42Smillert 
4906fe57b42Smillert 	/* Change which partition? */
4916fe57b42Smillert 	if (p == NULL) {
4926fe57b42Smillert 		p = getstring(lp, "partition to modify",
4936fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
4946fe57b42Smillert 	}
4956fe57b42Smillert 	partno = p[0] - 'a';
4966fe57b42Smillert 	pp = &lp->d_partitions[partno];
4976fe57b42Smillert 	origpart = lp->d_partitions[partno];
4986fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
4996fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
5006fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
5016fe57b42Smillert 		return;
5026fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
5036fe57b42Smillert 	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {
5046fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
5056fe57b42Smillert 		return;
5066fe57b42Smillert 	}
5076fe57b42Smillert 
5086fe57b42Smillert 	/* Get filesystem type */
5096fe57b42Smillert 	if (pp->p_fstype < FSMAXTYPES) {
5106fe57b42Smillert 		p = getstring(lp, "FS type",
5116fe57b42Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
5126fe57b42Smillert 		    fstypenames[pp->p_fstype]);
5136fe57b42Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
5146fe57b42Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
5156fe57b42Smillert 				pp->p_fstype = ui;
5166fe57b42Smillert 				break;
5176fe57b42Smillert 			}
5186fe57b42Smillert 		}
5196fe57b42Smillert 		if (ui >= FSMAXTYPES) {
5206fe57b42Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
5216fe57b42Smillert 			pp->p_fstype = FS_OTHER;
5226fe57b42Smillert 		}
5236fe57b42Smillert 	} else {
5246fe57b42Smillert 		for (;;) {
5256fe57b42Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
5266fe57b42Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
5276fe57b42Smillert 			    pp->p_fstype, pp->p_fstype, 0);
5286fe57b42Smillert 			if (ui == UINT_MAX)
5296fe57b42Smillert 				fputs("Invalid entry\n", stderr);
5306fe57b42Smillert 			else
5316fe57b42Smillert 				break;
5326fe57b42Smillert 		}
5336fe57b42Smillert 		pp->p_fstype = ui;
5346fe57b42Smillert 	}
5356fe57b42Smillert 
5366fe57b42Smillert 	/* Did they disable/enable the partition? */
537229f463eSmillert 	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&
538229f463eSmillert 	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)
5396fe57b42Smillert 		*freep += origpart.p_size;
540229f463eSmillert 	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&
541229f463eSmillert 	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {
5426fe57b42Smillert 		if (pp->p_size > *freep) {
5436fe57b42Smillert 			fprintf(stderr,
5446fe57b42Smillert 			    "Warning, need %u blocks but there are only %u "
5456fe57b42Smillert 			    "free.  Setting size to %u.\n", pp->p_size, *freep,
5466fe57b42Smillert 			    *freep);
5476fe57b42Smillert 			pp->p_fstype = *freep;
5486fe57b42Smillert 			*freep = 0;
5496fe57b42Smillert 		} else
5506fe57b42Smillert 			*freep -= pp->p_size;		/* have enough space */
5516fe57b42Smillert 	}
5526fe57b42Smillert 
5536fe57b42Smillert getoff2:
5546fe57b42Smillert 	/* Get offset */
5556fe57b42Smillert 	for (;;) {
5566fe57b42Smillert 		ui = getuint(lp, partno, "offset",
5576fe57b42Smillert 		    "Starting sector for this partition.", pp->p_offset,
5586fe57b42Smillert 		    pp->p_offset, DO_CONVERSIONS |
5596fe57b42Smillert 		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
5606fe57b42Smillert 		if (ui == UINT_MAX)
5616fe57b42Smillert 			fputs("Invalid entry\n", stderr);
5626fe57b42Smillert 		else
5636fe57b42Smillert 			break;
5646fe57b42Smillert 	}
5656fe57b42Smillert 	pp->p_offset = ui;
5666fe57b42Smillert 
5676fe57b42Smillert 	/* Get size */
5686fe57b42Smillert 	/* XXX - this loop sucks */
5696fe57b42Smillert 	for (;;) {
5706fe57b42Smillert 		ui = getuint(lp, partno, "size", "Size of the partition.",
5716fe57b42Smillert 		    pp->p_size, *freep, 1);
5726fe57b42Smillert 
5736fe57b42Smillert 		if (ui == pp->p_size)
5746fe57b42Smillert 			break;			/* no change */
5756fe57b42Smillert 
5766fe57b42Smillert 		if (ui == UINT_MAX) {
5776fe57b42Smillert 			fputs("Invalid entry\n", stderr);
5786fe57b42Smillert 			continue;
5796fe57b42Smillert 		} else if (partno != 2 && ui + pp->p_offset >
5806fe57b42Smillert 		    lp->d_partitions[2].p_size + lp->d_partitions[2].p_offset) {
5816fe57b42Smillert 			fputs("Partition must not extend past 'c'\n", stderr);
5826fe57b42Smillert 			continue;
5836fe57b42Smillert 		} else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) {
5846fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
5856fe57b42Smillert 			    stderr);
5866fe57b42Smillert 			continue;
5876fe57b42Smillert 		}
5886fe57b42Smillert 
589229f463eSmillert 		if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) {
5906fe57b42Smillert 			pp->p_size = ui;	/* don't care what's free */
5916fe57b42Smillert 			break;
5926fe57b42Smillert 		} else {
5936fe57b42Smillert 			if (ui > pp->p_size + *freep)
5946fe57b42Smillert 				/* XXX - prompt user to steal space from another partition */
5956fe57b42Smillert 				fprintf(stderr,
5966fe57b42Smillert 				    "Size may not be larger than %u blocks\n",
5976fe57b42Smillert 				    pp->p_size + *freep);
5986fe57b42Smillert 			else {
5996fe57b42Smillert 				*freep += pp->p_size - ui;
6006fe57b42Smillert 				pp->p_size = ui;
6016fe57b42Smillert 				break;
6026fe57b42Smillert 			}
6036fe57b42Smillert 		}
6046fe57b42Smillert 	}
6056fe57b42Smillert 	if (pp->p_size == 0)
6066fe57b42Smillert 		return;
6076fe57b42Smillert 
6086fe57b42Smillert 	/* Check for overlap and restore if not resolved */
6096fe57b42Smillert 	if (has_overlap(lp, freep, 0)) {
6106fe57b42Smillert 		puts("\nPlease re-enter an offset and size");
6116fe57b42Smillert 		pp->p_offset = origpart.p_offset;
6126fe57b42Smillert 		pp->p_size = origpart.p_size;
6136fe57b42Smillert 		goto getoff2;		/* Yeah, I know... */
6146fe57b42Smillert 	}
6156fe57b42Smillert 
6166fe57b42Smillert 	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {
6176fe57b42Smillert 		/* get fsize */
6186fe57b42Smillert 		for (;;) {
6196fe57b42Smillert 			ui = getuint(lp, partno, "fragment size",
6206fe57b42Smillert 			    "Size of fs block fragments.  Usually 1024 or 512.",
6216fe57b42Smillert 			    pp->p_fsize, 1024, 0);
6226fe57b42Smillert 			if (ui == UINT_MAX)
6236fe57b42Smillert 				fputs("Invalid entry\n", stderr);
6246fe57b42Smillert 			else
6256fe57b42Smillert 				break;
6266fe57b42Smillert 		}
6276fe57b42Smillert 		pp->p_fsize = ui;
6286fe57b42Smillert 		if (pp->p_fsize == 0)
6296fe57b42Smillert 			puts("Zero fragment size implies zero block size");
6306fe57b42Smillert 
6316fe57b42Smillert 		/* get bsize */
6326fe57b42Smillert 		for (; pp->p_fsize > 0;) {
6336fe57b42Smillert 			ui = getuint(lp, partno, "block size",
6346fe57b42Smillert 			    "Size of filesystem blocks.  Usually 8192 or 4096.",
6356fe57b42Smillert 			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,
6366fe57b42Smillert 			    0);
6376fe57b42Smillert 
6386fe57b42Smillert 			/* sanity check */
6396fe57b42Smillert 			if (ui == UINT_MAX)
6406fe57b42Smillert 				fputs("Invalid entry\n", stderr);
6416fe57b42Smillert 			else if (ui % pp->p_fsize != 0)
6426fe57b42Smillert 				puts("Error: block size must be a multiple of the fragment size.");
6436fe57b42Smillert 			else if (ui / pp->p_fsize < 1)
6446fe57b42Smillert 				puts("Error: block size must be at least as big as fragment size.");
6456fe57b42Smillert 			else {
6466fe57b42Smillert 				pp->p_frag = ui / pp->p_fsize;
6476fe57b42Smillert 				break;
6486fe57b42Smillert 			}
6496fe57b42Smillert 		}
6506fe57b42Smillert 
6516fe57b42Smillert 		if (pp->p_fstype == FS_BSDFFS) {
6526fe57b42Smillert 			/* get cpg */
6536fe57b42Smillert 			for (;;) {
6546fe57b42Smillert 				ui = getuint(lp, partno, "cpg",
6556fe57b42Smillert 				    "Number of filesystem cylinders per group."
6566fe57b42Smillert 				    "  Usually 16 or 8.", pp->p_cpg, pp->p_cpg,
6576fe57b42Smillert 				    0);
6586fe57b42Smillert 				if (ui == UINT_MAX)
6596fe57b42Smillert 					fputs("Invalid entry\n", stderr);
6606fe57b42Smillert 				else
6616fe57b42Smillert 					break;
6626fe57b42Smillert 			}
6636fe57b42Smillert 			pp->p_cpg = ui;
6646fe57b42Smillert 		}
6656fe57b42Smillert 	}
6666fe57b42Smillert 
6676fe57b42Smillert 	/* Make sure things stay contiguous. */
6686fe57b42Smillert 	make_contiguous(lp);
6696fe57b42Smillert }
6706fe57b42Smillert 
6716fe57b42Smillert /*
6726fe57b42Smillert  * Delete an existing partition.
6736fe57b42Smillert  */
6746fe57b42Smillert void
6756fe57b42Smillert editor_delete(lp, freep, p)
6766fe57b42Smillert 	struct disklabel *lp;
6776fe57b42Smillert 	u_int32_t *freep;
6786fe57b42Smillert 	char *p;
6796fe57b42Smillert {
6806fe57b42Smillert 	int c;
6816fe57b42Smillert 
6826fe57b42Smillert 	if (p == NULL) {
6836fe57b42Smillert 		p = getstring(lp, "partition to delete",
6846fe57b42Smillert 		    "The letter of the partition to delete, a - p.", NULL);
6856fe57b42Smillert 	}
6866fe57b42Smillert 	c = p[0] - 'a';
6876fe57b42Smillert 	if (c < 0 || c >= lp->d_npartitions)
6886fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
6896fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
6906fe57b42Smillert 	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==
6916fe57b42Smillert 	    FS_UNUSED && lp->d_partitions[c].p_size == 0))
6926fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);
6936fe57b42Smillert 	else if (c == 2)
6946fe57b42Smillert 		fputs("You may not delete the 'c' partition.\n", stderr);
6956fe57b42Smillert 	else {
6966fe57b42Smillert 		/* Update free block count. */
6976fe57b42Smillert 		if (lp->d_partitions[c].p_fstype != FS_UNUSED &&
698229f463eSmillert 		    lp->d_partitions[c].p_fstype != FS_BOOT &&
6996fe57b42Smillert 		    lp->d_partitions[c].p_size != 0)
7006fe57b42Smillert 			*freep += lp->d_partitions[c].p_size;
7016fe57b42Smillert 
7026fe57b42Smillert 		/* Really delete it (as opposed to just setting to "unused") */
7036fe57b42Smillert 		(void)memset(&lp->d_partitions[c], 0,
7046fe57b42Smillert 		    sizeof(lp->d_partitions[c]));
7056fe57b42Smillert 
7066fe57b42Smillert 		/* Fill in the gap we just made */
7076fe57b42Smillert 		make_contiguous(lp);
7086fe57b42Smillert 	}
7096fe57b42Smillert }
7106fe57b42Smillert 
7116fe57b42Smillert /*
7126fe57b42Smillert  * Simplified display() for use with the builtin editor.
7136fe57b42Smillert  */
7146fe57b42Smillert void
7156fe57b42Smillert editor_display(lp, freep, unit)
7166fe57b42Smillert 	struct disklabel *lp;
7176fe57b42Smillert 	u_int32_t *freep;
7186fe57b42Smillert 	char unit;
7196fe57b42Smillert {
7206fe57b42Smillert 	int i;
7216fe57b42Smillert 
7226fe57b42Smillert 	printf("device: %s\n", specname);
7230f820bbbSmillert 	printf("type: %s\n", dktypenames[lp->d_type]);
7246fe57b42Smillert 	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);
7256fe57b42Smillert 	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);
7266fe57b42Smillert 	printf("bytes/sector: %ld\n", (long)lp->d_secsize);
7276fe57b42Smillert 	printf("sectors/track: %ld\n", (long)lp->d_nsectors);
7286fe57b42Smillert 	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);
7296fe57b42Smillert 	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);
7306fe57b42Smillert 	printf("cylinders: %ld\n", (long)lp->d_ncylinders);
7316fe57b42Smillert 	printf("total sectors: %ld\n", (long)lp->d_secperunit);
7326fe57b42Smillert 	printf("free sectors: %u\n", *freep);
7336fe57b42Smillert 	printf("rpm: %ld\n", (long)lp->d_rpm);
7346fe57b42Smillert 	printf("\n%d partitions:\n", lp->d_npartitions);
7356fe57b42Smillert 	printf("#        size   offset    fstype   [fsize bsize   cpg]\n");
7366fe57b42Smillert 	for (i = 0; i < lp->d_npartitions; i++)
7376fe57b42Smillert 		display_partition(stdout, lp, i, unit);
7386fe57b42Smillert }
7396fe57b42Smillert 
7406fe57b42Smillert /*
7416fe57b42Smillert  * Find the next reasonable starting offset and returns it.
7426fe57b42Smillert  * Assumes there is a least one free block left (returns 0 if not).
7436fe57b42Smillert  */
7446fe57b42Smillert u_int32_t
7456fe57b42Smillert next_offset(lp)
7466fe57b42Smillert 	struct disklabel *lp;
7476fe57b42Smillert {
748f0b4d0a9Smillert 	struct partition **spp;
749f0b4d0a9Smillert 	u_int16_t npartitions;
7506fe57b42Smillert 	u_int32_t new_offset = 0;
7516fe57b42Smillert 	int i;
7526fe57b42Smillert 
753a7e61405Smillert 	/* Get a sorted list of the partitions */
754a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
755f0b4d0a9Smillert 
756f0b4d0a9Smillert 	for (i = 0; i < npartitions; i++ ) {
7576fe57b42Smillert 		/*
7586fe57b42Smillert 		 * Is new_offset inside this partition?  If so,
7596fe57b42Smillert 		 * make it the next block after the partition ends.
7606fe57b42Smillert 		 */
761f0b4d0a9Smillert 		if (new_offset >= spp[i]->p_offset &&
762f0b4d0a9Smillert 		    new_offset < spp[i]->p_offset + spp[i]->p_size)
763f0b4d0a9Smillert 			new_offset = spp[i]->p_offset + spp[i]->p_size;
7646fe57b42Smillert 	}
7656fe57b42Smillert 
766f0b4d0a9Smillert 	(void)free(spp);
7676fe57b42Smillert 	return(new_offset);
7686fe57b42Smillert }
7696fe57b42Smillert 
7706fe57b42Smillert /*
7716fe57b42Smillert  * Change the size of an existing partition.
7726fe57b42Smillert  */
7736fe57b42Smillert void
7746fe57b42Smillert editor_change(lp, freep, p)
7756fe57b42Smillert 	struct disklabel *lp;
7766fe57b42Smillert 	u_int32_t *freep;
7776fe57b42Smillert 	char *p;
7786fe57b42Smillert {
7796fe57b42Smillert 	int partno;
7806fe57b42Smillert 	u_int32_t newsize;
7816fe57b42Smillert 
7826fe57b42Smillert 	if (p == NULL) {
7836fe57b42Smillert 		p = getstring(lp, "partition to change size",
7846fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
7856fe57b42Smillert 	}
7866fe57b42Smillert 	partno = p[0] - 'a';
7876fe57b42Smillert 	if (partno < 0 || partno >= lp->d_npartitions) {
7886fe57b42Smillert 		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",
7896fe57b42Smillert 		    'a' + lp->d_npartitions - 1);
7906fe57b42Smillert 		return;
7916fe57b42Smillert 	} else if (partno >= lp->d_npartitions ||
792229f463eSmillert 	    lp->d_partitions[partno].p_size == 0) {
7936fe57b42Smillert 		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);
7946fe57b42Smillert 		return;
7956fe57b42Smillert 	}
7966fe57b42Smillert 
7976fe57b42Smillert 	printf("Partition %c is currently %u sectors in size (%u free).\n",
7986fe57b42Smillert 	    partno + 'a', lp->d_partitions[partno].p_size, *freep);
799229f463eSmillert 	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */
8006fe57b42Smillert 	newsize = getuint(lp, partno, "new size", "Size of the partition.  "
8016fe57b42Smillert 	    "You may also say +/- amount for a relative change.",
8026fe57b42Smillert 	    lp->d_partitions[partno].p_size,
8036fe57b42Smillert 	    lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS |
8046fe57b42Smillert 	    (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
8056fe57b42Smillert 	if (newsize == UINT_MAX) {
8066fe57b42Smillert 		fputs("Invalid entry\n", stderr);
8076fe57b42Smillert 		return;
8086fe57b42Smillert 	} else if (newsize == lp->d_partitions[partno].p_size)
8096fe57b42Smillert 		return;
8106fe57b42Smillert 
811229f463eSmillert 	if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&
812229f463eSmillert 	    lp->d_partitions[partno].p_fstype != FS_BOOT) {
8136fe57b42Smillert 		if (newsize > lp->d_partitions[partno].p_size) {
8146fe57b42Smillert 			if (newsize - lp->d_partitions[partno].p_size > *freep) {
8156fe57b42Smillert 				fprintf(stderr,
8166fe57b42Smillert 				    "Only %u sectors free, you asked for %u\n",
8176fe57b42Smillert 				    *freep,
8186fe57b42Smillert 				    newsize - lp->d_partitions[partno].p_size);
8196fe57b42Smillert 				return;
8206fe57b42Smillert 			}
8216fe57b42Smillert 			*freep -= newsize - lp->d_partitions[partno].p_size;
8226fe57b42Smillert 		} else if (newsize < lp->d_partitions[partno].p_size) {
8236fe57b42Smillert 			*freep += lp->d_partitions[partno].p_size - newsize;
8246fe57b42Smillert 		}
8256fe57b42Smillert 	} else {
8266fe57b42Smillert 		if (partno != 2 && newsize + lp->d_partitions[partno].p_offset >
8276fe57b42Smillert 		    lp->d_partitions[2].p_size) {
8286fe57b42Smillert 			fputs("Partition must not extend past 'c'\n", stderr);
8296fe57b42Smillert 			return;
8306fe57b42Smillert 		} else if (partno == 2 && newsize +
8316fe57b42Smillert 		    lp->d_partitions[partno].p_offset > lp->d_secperunit) {
8326fe57b42Smillert 			fputs("'c' partition may not be larger than the disk\n",
8336fe57b42Smillert 			    stderr);
8346fe57b42Smillert 			return;
8356fe57b42Smillert 		}
8366fe57b42Smillert 	}
8376fe57b42Smillert 	lp->d_partitions[partno].p_size = newsize;
8386fe57b42Smillert 	make_contiguous(lp);
8396fe57b42Smillert }
8406fe57b42Smillert 
8416fe57b42Smillert void
8426fe57b42Smillert make_contiguous(lp)
8436fe57b42Smillert 	struct disklabel *lp;
8446fe57b42Smillert {
8456fe57b42Smillert 	struct partition **spp;
8466fe57b42Smillert 	u_int16_t npartitions;
8476fe57b42Smillert 	int i;
8486fe57b42Smillert 
849a7e61405Smillert 	/* Get a sorted list of the partitions */
850a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
8516fe57b42Smillert 
8526fe57b42Smillert 	/*
853a7e61405Smillert 	 * Make everything contiguous but don't muck with start of the first one
8546fe57b42Smillert 	 */
8556fe57b42Smillert 	for (i = 1; i < npartitions; i++)
8566fe57b42Smillert 		spp[i]->p_offset = spp[i - 1]->p_offset + spp[i - 1]->p_size;
857f0b4d0a9Smillert 
858f0b4d0a9Smillert 	(void)free(spp);
8596fe57b42Smillert }
8606fe57b42Smillert 
8616fe57b42Smillert /*
8626fe57b42Smillert  * Sort the partitions based on starting offset.
8636fe57b42Smillert  * This assumes there can be no overlap.
8646fe57b42Smillert  */
8656fe57b42Smillert int
8666fe57b42Smillert partition_cmp(e1, e2)
8676fe57b42Smillert 	const void *e1, *e2;
8686fe57b42Smillert {
8696fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
8706fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
8716fe57b42Smillert 
8726fe57b42Smillert 	return((int)(p1->p_offset - p2->p_offset));
8736fe57b42Smillert }
8746fe57b42Smillert 
8756fe57b42Smillert char *
8766fe57b42Smillert getstring(lp, prompt, helpstring, oval)
8776fe57b42Smillert 	struct disklabel *lp;
8786fe57b42Smillert 	char *prompt;
8796fe57b42Smillert 	char *helpstring;
8806fe57b42Smillert 	char *oval;
8816fe57b42Smillert {
8826fe57b42Smillert 	static char buf[BUFSIZ];
8836fe57b42Smillert 	int n;
8846fe57b42Smillert 
8856fe57b42Smillert 	buf[0] = '\0';
8866fe57b42Smillert 	do {
8876fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
8886fe57b42Smillert 		fflush(stdout);
8896fe57b42Smillert 		rewind(stdin);
8906e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
8916e0becc5Smillert 			putchar('\n');
892260513deSmillert 			buf[0] = '\0';
8936e0becc5Smillert 		}
8946fe57b42Smillert 		n = strlen(buf);
8956fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
8966fe57b42Smillert 			buf[--n] = '\0';
8976fe57b42Smillert 		if (buf[0] == '?')
8986fe57b42Smillert 			puts(helpstring);
8996fe57b42Smillert 		else if (oval != NULL && buf[0] == '\0') {
9006fe57b42Smillert 			(void)strncpy(buf, oval, sizeof(buf) - 1);
9016fe57b42Smillert 			buf[sizeof(buf) - 1] = '\0';
9026fe57b42Smillert 		}
9036fe57b42Smillert 	} while (buf[0] == '?');
9046fe57b42Smillert 
9056fe57b42Smillert 	return(&buf[0]);
9066fe57b42Smillert }
9076fe57b42Smillert 
9086fe57b42Smillert /*
9096fe57b42Smillert  * Returns UINT_MAX on error
9106fe57b42Smillert  * XXX - there are way too many parameters here.  Use inline helper functions
9116fe57b42Smillert  */
9126fe57b42Smillert u_int32_t
9136fe57b42Smillert getuint(lp, partno, prompt, helpstring, oval, maxval, flags)
9146fe57b42Smillert 	struct disklabel *lp;
9156fe57b42Smillert 	int partno;
9166fe57b42Smillert 	char *prompt;
9176fe57b42Smillert 	char *helpstring;
9186fe57b42Smillert 	u_int32_t oval;
9196fe57b42Smillert 	u_int32_t maxval;		/* XXX - used inconsistently */
9206fe57b42Smillert 	int flags;
9216fe57b42Smillert {
9226fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
9236fe57b42Smillert 	u_int32_t rval = oval;
9246fe57b42Smillert 	size_t n;
9256fe57b42Smillert 	int mult = 1;
9266fe57b42Smillert 	u_long ul;
9276fe57b42Smillert 
9286fe57b42Smillert 	buf[0] = '\0';
9296fe57b42Smillert 	do {
9306fe57b42Smillert 		printf("%s: [%u] ", prompt, oval);
9316fe57b42Smillert 		fflush(stdout);
9326fe57b42Smillert 		rewind(stdin);
9336e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
9346e0becc5Smillert 			putchar('\n');
9356e0becc5Smillert 			buf[0] = '\0';
9366e0becc5Smillert 		}
9376fe57b42Smillert 		n = strlen(buf);
9386fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
9396fe57b42Smillert 			buf[--n] = '\0';
9406fe57b42Smillert 		if (buf[0] == '?')
9416fe57b42Smillert 			puts(helpstring);
9426fe57b42Smillert 	} while (buf[0] == '?');
9436fe57b42Smillert 
9446fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
9456fe57b42Smillert 		rval = maxval;
9466fe57b42Smillert 	} else {
9476fe57b42Smillert 		/* deal with units */
9486fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
9496fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
9506fe57b42Smillert 				switch (buf[n-1]) {
9516fe57b42Smillert 
9526fe57b42Smillert 				case 'c':
9536fe57b42Smillert 					mult = lp->d_secpercyl;
9546fe57b42Smillert 					buf[--n] = '\0';
9556fe57b42Smillert 					break;
9566fe57b42Smillert 				case 'b':
9576fe57b42Smillert 					mult = -lp->d_secsize;
9586fe57b42Smillert 					buf[--n] = '\0';
9596fe57b42Smillert 					break;
9606fe57b42Smillert 				case 'k':
9616fe57b42Smillert 					mult = 1024 / lp->d_secsize;
9626fe57b42Smillert 					buf[--n] = '\0';
9636fe57b42Smillert 					break;
9646fe57b42Smillert 				case 'm':
9656fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
9666fe57b42Smillert 					buf[--n] = '\0';
9676fe57b42Smillert 					break;
9681a51a1eeSmillert 				case 'g':
9691a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
9701a51a1eeSmillert 					buf[--n] = '\0';
9711a51a1eeSmillert 					break;
9726fe57b42Smillert 				}
9736fe57b42Smillert 			} else
9746fe57b42Smillert 				mult = 1;
9756fe57b42Smillert 
9766fe57b42Smillert 			/* Did they give us an operator? */
9776fe57b42Smillert 			p = &buf[0];
9786fe57b42Smillert 			if (*p == '+' || *p == '-')
9796fe57b42Smillert 				operator = *p++;
9806fe57b42Smillert 
9816fe57b42Smillert 			endptr = p;
9826fe57b42Smillert 			if (mult > 0)
9836fe57b42Smillert 				ul = strtoul(p, &endptr, 10) * mult;
9846fe57b42Smillert 			else
9856fe57b42Smillert 				/* Negative mult means divide (ooh, fancy) */
9866fe57b42Smillert 				ul = strtoul(p, &endptr, 10) / (-mult);
9876fe57b42Smillert 
9886fe57b42Smillert 			/* Sanity check the return val */
9896fe57b42Smillert 			if (ul == ULONG_MAX || ul >= UINT_MAX) {
9906fe57b42Smillert 				errno = ERANGE;		/* too big */
9916fe57b42Smillert 				rval = UINT_MAX;
9926fe57b42Smillert 			} else if (*endptr != '\0') {
9936fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
9946fe57b42Smillert 				rval = UINT_MAX;
9956fe57b42Smillert 			} else {
9966fe57b42Smillert 				rval = ul;
9976fe57b42Smillert 
9986fe57b42Smillert 				/* Apply the operator (XXX - check for oflow) */
9996fe57b42Smillert 				if (operator == '+')
10006fe57b42Smillert 					rval += oval;
10016fe57b42Smillert 				else if (operator == '-')
10026fe57b42Smillert 					rval = oval - rval;
10036fe57b42Smillert 			}
10046fe57b42Smillert 		}
10056fe57b42Smillert 	}
10066fe57b42Smillert 	if ((flags & DO_ROUNDING) && rval < UINT_MAX) {
10076fe57b42Smillert 		u_int32_t cyls;
1008260513deSmillert 		/* XXX - should use maxsize and round down if too big */
10096fe57b42Smillert #ifdef CYLCHECK
10106fe57b42Smillert 		/* Always round to nearest cylinder, regardless of units */
10116fe57b42Smillert 		cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5);
10126fe57b42Smillert 		if (rval != cyls * lp->d_secpercyl) {
10136fe57b42Smillert 			rval = cyls * lp->d_secpercyl;
10146fe57b42Smillert 			printf("Rounding to nearest cylinder: %u\n", rval);
10156fe57b42Smillert 		}
10166fe57b42Smillert #else
10176fe57b42Smillert 		/* Round to nearest cylinder unless given in blocks */
10186fe57b42Smillert 		if (mult > 1) {
10196fe57b42Smillert 			cyls = (u_int32_t)((rval / (double)lp->d_secpercyl)
10206fe57b42Smillert 			    + 0.5);
10216fe57b42Smillert 			if (rval != cyls * lp->d_secpercyl) {
10226fe57b42Smillert 				rval = cyls * lp->d_secpercyl;
10236fe57b42Smillert 				printf("Rounding to nearest cylinder: %u\n",
10246fe57b42Smillert 				    rval);
10256fe57b42Smillert 			}
10266fe57b42Smillert 		}
10276fe57b42Smillert #endif
10286fe57b42Smillert 	}
10296fe57b42Smillert 
10306fe57b42Smillert 	return(rval);
10316fe57b42Smillert }
10326fe57b42Smillert 
10336fe57b42Smillert /*
10346fe57b42Smillert  * Check for partition overlap in lp and prompt the user
10356fe57b42Smillert  * to resolve the overlap if any is found.  Returns 1
10366fe57b42Smillert  * if unable to resolve, else 0.
10376fe57b42Smillert  */
10386fe57b42Smillert int
10396fe57b42Smillert has_overlap(lp, freep, resolve)
10406fe57b42Smillert 	struct disklabel *lp;
10416fe57b42Smillert 	u_int32_t *freep;
10426fe57b42Smillert 	int resolve;
10436fe57b42Smillert {
10446fe57b42Smillert 	struct partition **spp;
10456fe57b42Smillert 	u_int16_t npartitions;
10466fe57b42Smillert 	int c, i, j, rval = 0;
10476fe57b42Smillert 
1048a7e61405Smillert 	/* Get a sorted list of the partitions */
1049a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
10506fe57b42Smillert 
1051a7e61405Smillert 	if (npartitions < 2) {
1052a7e61405Smillert 		(void)free(spp);
10536fe57b42Smillert 		return(0);			/* nothing to do */
10546fe57b42Smillert 	}
10556fe57b42Smillert 
10566fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
10576fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
10586fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
10596fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
10606fe57b42Smillert 			if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) {
10616fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
10626fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
10636fe57b42Smillert 				    / sizeof(**spp);
10646fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
10656fe57b42Smillert 				    / sizeof(**spp);
10666fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
10676fe57b42Smillert 				    'a' + i, 'a' + j);
10686fe57b42Smillert 				puts("         size   offset    fstype   [fsize bsize   cpg]");
10696fe57b42Smillert 				display_partition(stdout, lp, i, 0);
10706fe57b42Smillert 				display_partition(stdout, lp, j, 0);
10716fe57b42Smillert 
10726fe57b42Smillert 				/* Did they ask us to resolve it ourselves? */
1073f0b4d0a9Smillert 				if (!resolve) {
1074f0b4d0a9Smillert 					(void)free(spp);
10756fe57b42Smillert 					return(1);
1076f0b4d0a9Smillert 				}
10776fe57b42Smillert 
10786fe57b42Smillert 				printf("Disable which one? [%c %c] ",
10796fe57b42Smillert 				    'a' + i, 'a' + j);
10806fe57b42Smillert 				/* XXX - make less gross */
10816fe57b42Smillert 				while ((c = getchar()) != EOF && c != '\n') {
10826fe57b42Smillert 					c -= 'a';
10836fe57b42Smillert 					if (c == i || c == j)
10846fe57b42Smillert 						break;
10856fe57b42Smillert 				}
10866fe57b42Smillert 				putchar('\n');
10876fe57b42Smillert 				/* Mark the selected one as unused or... */
10886fe57b42Smillert 				if (c == i || c == j) {
10896fe57b42Smillert 					lp->d_partitions[c].p_fstype = FS_UNUSED;
10906fe57b42Smillert 					*freep += lp->d_partitions[c].p_size;
10916fe57b42Smillert 				} else
10926fe57b42Smillert 					rval = 1;	/* still has overlap */
10936fe57b42Smillert 			    }
10946fe57b42Smillert 		}
10956fe57b42Smillert 	}
1096f0b4d0a9Smillert 
1097f0b4d0a9Smillert 	(void)free(spp);
10986fe57b42Smillert 	return(rval);
10996fe57b42Smillert }
11006fe57b42Smillert 
11016fe57b42Smillert void
11026fe57b42Smillert edit_parms(lp, freep)
11036fe57b42Smillert 	struct disklabel *lp;
11046fe57b42Smillert 	u_int32_t *freep;
11056fe57b42Smillert {
11066fe57b42Smillert 	char *p;
11076fe57b42Smillert 	u_int32_t ui;
11086fe57b42Smillert 
1109*ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
11106fe57b42Smillert 
11110f820bbbSmillert 	/* disk type */
11120f820bbbSmillert 	for (;;) {
11130f820bbbSmillert 		p = getstring(lp, "disk type",
11140f820bbbSmillert 		    "What kind of disk is this?  Usually SCSI, ST506, or "
11150f820bbbSmillert 		    "floppy (use ST506 for IDE).", dktypenames[lp->d_type]);
11160f820bbbSmillert 		for (ui = 1; ui < DKMAXTYPES && strcasecmp(p, dktypenames[ui]);
11170f820bbbSmillert 		    ui++)
11180f820bbbSmillert 			;
11190f820bbbSmillert 		if (ui < DKMAXTYPES) {
11200f820bbbSmillert 			break;
11210f820bbbSmillert 		} else {
11220f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
11230f820bbbSmillert 			fputs("Valid types are: ", stdout);
11240f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
11250f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
11260f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
11270f820bbbSmillert 					fputs(", ", stdout);
11280f820bbbSmillert 			}
11290f820bbbSmillert 			putchar('\n');
11300f820bbbSmillert 		}
11310f820bbbSmillert 	}
11320f820bbbSmillert 	lp->d_type = ui;
11330f820bbbSmillert 
11346fe57b42Smillert 	/* pack/label id */
11356fe57b42Smillert 	p = getstring(lp, "label name",
11366fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
11376fe57b42Smillert 	    lp->d_packname);
11386fe57b42Smillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1);
11396fe57b42Smillert 	lp->d_packname[sizeof(lp->d_packname) - 1] = '\0';
11406fe57b42Smillert 
11416fe57b42Smillert 	/* sectors/track */
11426fe57b42Smillert 	for (;;) {
11436fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
11446fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
11456fe57b42Smillert 		    lp->d_nsectors, 0);
11466fe57b42Smillert 		if (ui == UINT_MAX)
11476fe57b42Smillert 			fputs("Invalid entry\n", stderr);
11486fe57b42Smillert 		else
11496fe57b42Smillert 			break;
11506fe57b42Smillert 	}
11516fe57b42Smillert 	lp->d_nsectors = ui;
11526fe57b42Smillert 
11536fe57b42Smillert 	/* tracks/cylinder */
11546fe57b42Smillert 	for (;;) {
11556fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
11566fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
11576fe57b42Smillert 		    lp->d_ntracks, 0);
11586fe57b42Smillert 		if (ui == UINT_MAX)
11596fe57b42Smillert 			fputs("Invalid entry\n", stderr);
11606fe57b42Smillert 		else
11616fe57b42Smillert 			break;
11626fe57b42Smillert 	}
11636fe57b42Smillert 	lp->d_ntracks = ui;
11646fe57b42Smillert 
11656fe57b42Smillert 	/* sectors/cylinder */
11666fe57b42Smillert 	lp->d_ncylinders = lp->d_ntracks * lp->d_nsectors;
11676fe57b42Smillert 
11686fe57b42Smillert 	/* number of cylinders */
11696fe57b42Smillert 	for (;;) {
11706fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
11716fe57b42Smillert 		    "The total number of cylinders on the disk.",
11726fe57b42Smillert 		    lp->d_ncylinders, lp->d_ncylinders, 0);
11736fe57b42Smillert 		if (ui == UINT_MAX)
11746fe57b42Smillert 			fputs("Invalid entry\n", stderr);
11756fe57b42Smillert 		else
11766fe57b42Smillert 			break;
11776fe57b42Smillert 	}
11786fe57b42Smillert 	lp->d_ncylinders = ui;
11796fe57b42Smillert 
11806fe57b42Smillert 	/* total sectors */
11816fe57b42Smillert 	for (;;) {
11826fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
11836fe57b42Smillert 		    "The total number of sectors on the disk.",
11846fe57b42Smillert 		    lp->d_secperunit ? lp->d_secperunit :
11856fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders,
11866fe57b42Smillert 		    lp->d_ncylinders * lp->d_ncylinders, 0);
11876fe57b42Smillert 		if (ui == UINT_MAX)
11886fe57b42Smillert 			fputs("Invalid entry\n", stderr);
11896fe57b42Smillert 		else if (ui > lp->d_secperunit) {
11906fe57b42Smillert 			/* grow free count */
11916fe57b42Smillert 			*freep += ui - lp->d_secperunit;
11926fe57b42Smillert 			puts("You may want to increase the 'c' partition.");
11936fe57b42Smillert 			break;
11946fe57b42Smillert 		} else if (ui < lp->d_secperunit) {
11956fe57b42Smillert 			/* shrink free count */
11966fe57b42Smillert 			if (lp->d_secperunit - ui > *freep)
11976fe57b42Smillert 				fprintf(stderr,
11986fe57b42Smillert 				    "Not enough free space to shrink by %u "
11996fe57b42Smillert 				    "sectors (only %u sectors left)\n",
12006fe57b42Smillert 				    lp->d_secperunit - ui, *freep);
12016fe57b42Smillert 			else {
12026fe57b42Smillert 				*freep -= lp->d_secperunit - ui;
12036fe57b42Smillert 				break;
12046fe57b42Smillert 			}
12056fe57b42Smillert 		} else
12066fe57b42Smillert 			break;
12076fe57b42Smillert 	}
12086fe57b42Smillert 	lp->d_secperunit = ui;
12096fe57b42Smillert 
12106fe57b42Smillert 	/* rpm */
12116fe57b42Smillert 	for (;;) {
12126fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1213a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
12146fe57b42Smillert 		  lp->d_rpm, lp->d_rpm, 0);
12156fe57b42Smillert 		if (ui == UINT_MAX)
12166fe57b42Smillert 			fputs("Invalid entry\n", stderr);
12176fe57b42Smillert 		else
12186fe57b42Smillert 			break;
12196fe57b42Smillert 	}
12206fe57b42Smillert 	lp->d_rpm = ui;
12216fe57b42Smillert }
1222a7e61405Smillert 
1223a7e61405Smillert struct partition **
1224a7e61405Smillert sort_partitions(lp, npart)
1225a7e61405Smillert 	struct disklabel *lp;
1226a7e61405Smillert 	u_int16_t *npart;
1227a7e61405Smillert {
1228a7e61405Smillert 	u_int16_t npartitions;
1229a7e61405Smillert 	struct partition **spp;
1230a7e61405Smillert 	int i;
1231a7e61405Smillert 
1232a7e61405Smillert 	/* How many "real" partitions do we have? */
1233a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1234a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1235a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1236a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1237a7e61405Smillert 			npartitions++;
1238a7e61405Smillert 	}
1239a7e61405Smillert 
1240a7e61405Smillert 	/* Create an array of pointers to the partition data */
1241a7e61405Smillert 	if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL)
1242a7e61405Smillert 		errx(4, "out of memory");
1243a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1244a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1245a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
1246a7e61405Smillert 		    lp->d_partitions[i].p_size != 0)
1247a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1248a7e61405Smillert 	}
1249a7e61405Smillert 
1250a7e61405Smillert 	/*
1251a7e61405Smillert 	 * Sort the partitions based on starting offset.
1252a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1253a7e61405Smillert 	 */
1254a7e61405Smillert 	if (npartitions > 1)
1255a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1256a7e61405Smillert 		    partition_cmp))
1257a7e61405Smillert 			err(4, "failed to sort partition table");
1258a7e61405Smillert 
1259a7e61405Smillert 	*npart = npartitions;
1260a7e61405Smillert 	return(spp);
1261a7e61405Smillert }
12620f820bbbSmillert 
12630f820bbbSmillert /*
12640f820bbbSmillert  * Get a valid disk type if necessary.
12650f820bbbSmillert  */
12660f820bbbSmillert void
12670f820bbbSmillert getdisktype(lp, banner)
12680f820bbbSmillert 	struct disklabel *lp;
12690f820bbbSmillert 	char *banner;
12700f820bbbSmillert {
12710f820bbbSmillert 	int i;
12720f820bbbSmillert 	char *s;
12730f820bbbSmillert 
12740f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
12750f820bbbSmillert 		puts(banner);
12760f820bbbSmillert 		puts("Possible values are:");
12770f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
12780f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
12790f820bbbSmillert 			if (i < DKMAXTYPES - 1)
12800f820bbbSmillert 				fputs(", ", stdout);
12810f820bbbSmillert 		}
12820f820bbbSmillert 		putchar('\n');
12830f820bbbSmillert 
12840f820bbbSmillert 		for (;;) {
12850f820bbbSmillert 			s = getstring(lp, "Disk type",
12860f820bbbSmillert 			    "What kind of disk is this?  Usually SCSI, ST506, or floppy (use ST506 for IDE).",
12870f820bbbSmillert 			    "SCSI");
12880f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
12890f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
12900f820bbbSmillert 					lp->d_type = i;
12910f820bbbSmillert 					putchar('\n');
12920f820bbbSmillert 					return;
12930f820bbbSmillert 				}
12940f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
12950f820bbbSmillert 			fputs("Valid types are: ", stdout);
12960f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
12970f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
12980f820bbbSmillert 				if (i < DKMAXTYPES - 1)
12990f820bbbSmillert 					fputs(", ", stdout);
13000f820bbbSmillert 			}
13010f820bbbSmillert 			putchar('\n');
13020f820bbbSmillert 		}
13030f820bbbSmillert 	}
13040f820bbbSmillert }
1305