xref: /openbsd/sbin/disklabel/editor.c (revision d18c2a43)
1*d18c2a43Skrw /*	$OpenBSD: editor.c,v 1.160 2008/01/22 00:06:25 krw Exp $	*/
26fe57b42Smillert 
36fe57b42Smillert /*
42d8451b0Smillert  * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com>
56fe57b42Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
96fe57b42Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176fe57b42Smillert  */
186fe57b42Smillert 
196fe57b42Smillert #ifndef lint
20*d18c2a43Skrw static char rcsid[] = "$OpenBSD: editor.c,v 1.160 2008/01/22 00:06:25 krw Exp $";
216fe57b42Smillert #endif /* not lint */
226fe57b42Smillert 
236fe57b42Smillert #include <sys/types.h>
246fe57b42Smillert #include <sys/param.h>
25c33fcabaSmillert #include <sys/stat.h>
26c33fcabaSmillert #include <sys/ioctl.h>
276fe57b42Smillert #define	DKTYPENAMES
286fe57b42Smillert #include <sys/disklabel.h>
296fe57b42Smillert 
306fe57b42Smillert #include <ufs/ffs/fs.h>
316fe57b42Smillert 
326fe57b42Smillert #include <ctype.h>
336fe57b42Smillert #include <err.h>
346fe57b42Smillert #include <errno.h>
356fe57b42Smillert #include <string.h>
36803ff7d5Smillert #include <libgen.h>
376fe57b42Smillert #include <stdio.h>
386fe57b42Smillert #include <stdlib.h>
396fe57b42Smillert #include <unistd.h>
406fe57b42Smillert 
41f21a098bSotto #include "extern.h"
424793b14cSmillert #include "pathnames.h"
434793b14cSmillert 
446fe57b42Smillert /* flags for getuint() */
456fe57b42Smillert #define	DO_CONVERSIONS	0x00000001
466fe57b42Smillert #define	DO_ROUNDING	0x00000002
476fe57b42Smillert 
48f98aebd4Smillert #ifndef NUMBOOT
49f98aebd4Smillert #define NUMBOOT 0
50f98aebd4Smillert #endif
51f98aebd4Smillert 
5296a888c6Smillert /* structure to describe a portion of a disk */
5396a888c6Smillert struct diskchunk {
541e0ad43cSotto 	u_int64_t start;
551e0ad43cSotto 	u_int64_t stop;
5696a888c6Smillert };
5796a888c6Smillert 
583f843443Smillert /* used when sorting mountpoints in mpsave() */
593f843443Smillert struct mountinfo {
603f843443Smillert 	char *mountpoint;
613f843443Smillert 	int partno;
623f843443Smillert };
633f843443Smillert 
649fdcb4d6Skrw void	edit_parms(struct disklabel *);
659fdcb4d6Skrw void	editor_add(struct disklabel *, char **, char *);
669fdcb4d6Skrw void	editor_change(struct disklabel *, char *);
679fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *);
689fdcb4d6Skrw void	editor_delete(struct disklabel *, char **, char *);
69c72b5b24Smillert void	editor_help(char *);
709fdcb4d6Skrw void	editor_modify(struct disklabel *, char **, char *);
71c72b5b24Smillert void	editor_name(struct disklabel *, char **, char *);
72c72b5b24Smillert char	*getstring(char *, char *, char *);
731e0ad43cSotto u_int64_t getuint(struct disklabel *, int, char *, char *, u_int64_t, u_int64_t, u_int64_t, int);
741f0f871dSkrw int	has_overlap(struct disklabel *);
75c72b5b24Smillert int	partition_cmp(const void *, const void *);
76c72b5b24Smillert struct partition **sort_partitions(struct disklabel *, u_int16_t *);
77c72b5b24Smillert void	getdisktype(struct disklabel *, char *, char *);
7887023ed9Skrw void	find_bounds(struct disklabel *);
799fdcb4d6Skrw void	set_bounds(struct disklabel *);
80c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *);
81c72b5b24Smillert char **	mpcopy(char **, char **);
82c72b5b24Smillert int	micmp(const void *, const void *);
83c72b5b24Smillert int	mpequal(char **, char **);
84c72b5b24Smillert int	mpsave(struct disklabel *, char **, char *, char *);
85c72b5b24Smillert int	get_bsize(struct disklabel *, int);
86c72b5b24Smillert int	get_fsize(struct disklabel *, int);
87c72b5b24Smillert int	get_fstype(struct disklabel *, int);
88c72b5b24Smillert int	get_mp(struct disklabel *, char **, int);
89604d3bdeSkrw int	get_offset(struct disklabel *, int);
909fdcb4d6Skrw int	get_size(struct disklabel *, int);
9187023ed9Skrw void	get_geometry(int, struct disklabel **);
9287023ed9Skrw void	set_geometry(struct disklabel *, struct disklabel *, struct disklabel *,
9387023ed9Skrw 	    char *);
949fdcb4d6Skrw void	zero_partitions(struct disklabel *);
9514192793Skrw u_int64_t max_partition_size(struct disklabel *, int);
9696a888c6Smillert 
971e0ad43cSotto static u_int64_t starting_sector;
981e0ad43cSotto static u_int64_t ending_sector;
992d8451b0Smillert static int expert;
1006fe57b42Smillert 
1016fe57b42Smillert /*
1026fe57b42Smillert  * Simple partition editor.  Primarily intended for new labels.
1036fe57b42Smillert  */
1046fe57b42Smillert int
1058809fabbSderaadt editor(struct disklabel *lp, int f, char *dev, char *fstabfile)
1066fe57b42Smillert {
1076fe57b42Smillert 	struct disklabel lastlabel, tmplabel, label = *lp;
10887023ed9Skrw 	struct disklabel *disk_geop;
10996a888c6Smillert 	struct partition *pp;
1106fe57b42Smillert 	FILE *fp;
1116fe57b42Smillert 	char buf[BUFSIZ], *cmd, *arg;
112a4df0321Sderaadt 	char **mountpoints = NULL, **omountpoints = NULL, **tmpmountpoints = NULL;
113bd6726faSmillert 
114bd6726faSmillert 	/* Alloc and init mount point info */
115bd6726faSmillert 	if (fstabfile) {
116bd6726faSmillert 		if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
117bd6726faSmillert 		    !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) ||
118bd6726faSmillert 		    !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *))))
119bd6726faSmillert 			errx(4, "out of memory");
120bd6726faSmillert 	}
1216fe57b42Smillert 
12296a888c6Smillert 	/* Don't allow disk type of "unknown" */
123803ff7d5Smillert 	getdisktype(&label, "You need to specify a type for this disk.", dev);
1246fe57b42Smillert 
12587023ed9Skrw 	/* Get the on-disk geometries if possible */
12687023ed9Skrw 	get_geometry(f, &disk_geop);
127c33fcabaSmillert 
128d09f3941Smillert 	/* How big is the OpenBSD portion of the disk?  */
12987023ed9Skrw 	find_bounds(&label);
130d09f3941Smillert 
13196a888c6Smillert 	/* Make sure there is no partition overlap. */
1321f0f871dSkrw 	if (has_overlap(&label))
1336fe57b42Smillert 		errx(1, "can't run when there is partition overlap.");
1346fe57b42Smillert 
13596a888c6Smillert 	/* If we don't have a 'c' partition, create one. */
136d09f3941Smillert 	pp = &label.d_partitions[RAW_PART];
1371e0ad43cSotto 	if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) {
13896a888c6Smillert 		puts("No 'c' partition found, adding one that spans the disk.");
13996a888c6Smillert 		if (label.d_npartitions < 3)
14096a888c6Smillert 			label.d_npartitions = 3;
14134af67a3Sotto 		DL_SETPOFFSET(pp, 0);
14234af67a3Sotto 		DL_SETPSIZE(pp, DL_GETDSIZE(&label));
14396a888c6Smillert 		pp->p_fstype = FS_UNUSED;
144ddfcbf38Sotto 		pp->p_fragblock = pp->p_cpg = 0;
14596a888c6Smillert 	}
1460f820bbbSmillert 
147fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
148fc1a4cc6Sderaadt 	if (label.d_flags & D_VENDOR) {
149fc1a4cc6Sderaadt 		puts("This platform requires that partition offsets/sizes "
150fc1a4cc6Sderaadt 		    "be on cylinder boundaries.\n"
151fc1a4cc6Sderaadt 		    "Partition offsets/sizes will be rounded to the "
152fc1a4cc6Sderaadt 		    "nearest cylinder automatically.");
153fc1a4cc6Sderaadt 	}
1546fe57b42Smillert #endif
1556fe57b42Smillert 
156bd6726faSmillert 	/* Set d_bbsize and d_sbsize as necessary */
15755403f76Smillert 	if (label.d_bbsize == 0)
15855403f76Smillert 		label.d_bbsize = BBSIZE;
15955403f76Smillert 	if (label.d_sbsize == 0)
16055403f76Smillert 		label.d_sbsize = SBSIZE;
161f98aebd4Smillert 
162440b1d70Smillert 	/* Interleave must be >= 1 */
163440b1d70Smillert 	if (label.d_interleave == 0)
164440b1d70Smillert 		label.d_interleave = 1;
165440b1d70Smillert 
1666893bfe5Sderaadt 	puts("Initial label editor (enter '?' for help at any prompt)");
1676fe57b42Smillert 	lastlabel = label;
1686fe57b42Smillert 	for (;;) {
1696fe57b42Smillert 		fputs("> ", stdout);
1706e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
1716e0becc5Smillert 			putchar('\n');
1726e0becc5Smillert 			buf[0] = 'q';
1736e0becc5Smillert 			buf[1] = '\0';
1746e0becc5Smillert 		}
175260513deSmillert 		if ((cmd = strtok(buf, " \t\r\n")) == NULL)
176260513deSmillert 			continue;
177260513deSmillert 		arg = strtok(NULL, " \t\r\n");
1786fe57b42Smillert 
1796fe57b42Smillert 		switch (*cmd) {
1806fe57b42Smillert 
1816fe57b42Smillert 		case '?':
182ea37abd3Sderaadt 		case 'h':
183617e6e4aSmillert 			editor_help(arg ? arg : "");
1846fe57b42Smillert 			break;
1856fe57b42Smillert 
1866fe57b42Smillert 		case 'a':
1876fe57b42Smillert 			tmplabel = lastlabel;
1886fe57b42Smillert 			lastlabel = label;
189bd6726faSmillert 			if (mountpoints != NULL) {
190bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
191bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
192bd6726faSmillert 			}
1939fdcb4d6Skrw 			editor_add(&label, mountpoints, arg);
19496a888c6Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
19596a888c6Smillert 				lastlabel = tmplabel;
196bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
197bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
19896a888c6Smillert 			break;
19996a888c6Smillert 
20096a888c6Smillert 		case 'b':
20196a888c6Smillert 			tmplabel = lastlabel;
20296a888c6Smillert 			lastlabel = label;
2039fdcb4d6Skrw 			set_bounds(&label);
2046fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2056fe57b42Smillert 				lastlabel = tmplabel;
2066fe57b42Smillert 			break;
2076fe57b42Smillert 
2086fe57b42Smillert 		case 'c':
2096fe57b42Smillert 			tmplabel = lastlabel;
2106fe57b42Smillert 			lastlabel = label;
2119fdcb4d6Skrw 			editor_change(&label, arg);
2126fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2136fe57b42Smillert 				lastlabel = tmplabel;
2146fe57b42Smillert 			break;
2156fe57b42Smillert 
2169afbe9eeSmillert 		case 'D':
217cdd7eb76Smillert 			tmplabel = lastlabel;
218cdd7eb76Smillert 			lastlabel = label;
21971bba4ecSkrw 			if (ioctl(f, DIOCGPDINFO, &label) == 0) {
22071bba4ecSkrw 				dflag = 1;
22171bba4ecSkrw 			} else {
222cdd7eb76Smillert 				warn("unable to get default partition table");
223cdd7eb76Smillert 				lastlabel = tmplabel;
224cdd7eb76Smillert 			}
2259afbe9eeSmillert 			break;
2269afbe9eeSmillert 
2276fe57b42Smillert 		case 'd':
2286fe57b42Smillert 			tmplabel = lastlabel;
2296fe57b42Smillert 			lastlabel = label;
230bd6726faSmillert 			if (mountpoints != NULL) {
231bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
232bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
233bd6726faSmillert 			}
2349fdcb4d6Skrw 			editor_delete(&label, mountpoints, arg);
2356fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2366fe57b42Smillert 				lastlabel = tmplabel;
237bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
238bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
2396fe57b42Smillert 			break;
2406fe57b42Smillert 
2419afbe9eeSmillert 		case 'e':
2429afbe9eeSmillert 			tmplabel = lastlabel;
2439afbe9eeSmillert 			lastlabel = label;
2449fdcb4d6Skrw 			edit_parms(&label);
2459afbe9eeSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2469afbe9eeSmillert 				lastlabel = tmplabel;
2479afbe9eeSmillert 			break;
2489afbe9eeSmillert 
249c33fcabaSmillert 		case 'g':
250c33fcabaSmillert 			tmplabel = lastlabel;
251c33fcabaSmillert 			lastlabel = label;
25287023ed9Skrw 			set_geometry(&label, disk_geop, lp, arg);
253c33fcabaSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
254c33fcabaSmillert 				lastlabel = tmplabel;
255c33fcabaSmillert 			break;
256c33fcabaSmillert 
2576fe57b42Smillert 		case 'm':
2586fe57b42Smillert 			tmplabel = lastlabel;
2596fe57b42Smillert 			lastlabel = label;
260bd6726faSmillert 			if (mountpoints != NULL) {
261bd6726faSmillert 				mpcopy(tmpmountpoints, omountpoints);
262bd6726faSmillert 				mpcopy(omountpoints, mountpoints);
263bd6726faSmillert 			}
2649fdcb4d6Skrw 			editor_modify(&label, mountpoints, arg);
2656fe57b42Smillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)
2666fe57b42Smillert 				lastlabel = tmplabel;
267bd6726faSmillert 			if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints))
268bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
269bd6726faSmillert 			break;
270bd6726faSmillert 
271bd6726faSmillert 		case 'n':
272bd6726faSmillert 			if (mountpoints == NULL) {
273bd6726faSmillert 				fputs("This option is not valid when run "
27484d0bb16Sderaadt 				    "without the -f flag.\n", stderr);
275bd6726faSmillert 				break;
276bd6726faSmillert 			}
277bd6726faSmillert 			mpcopy(tmpmountpoints, omountpoints);
278bd6726faSmillert 			mpcopy(omountpoints, mountpoints);
279bd6726faSmillert 			editor_name(&label, mountpoints, arg);
280bd6726faSmillert 			if (mpequal(omountpoints, tmpmountpoints))
281bd6726faSmillert 				mpcopy(omountpoints, tmpmountpoints);
2826fe57b42Smillert 			break;
2836fe57b42Smillert 
2846fe57b42Smillert 		case 'p':
2855b19a791Sotto 			display(stdout, &label, mountpoints, arg ? *arg : 0, 1,
2869fdcb4d6Skrw 			    editor_countfree(&label));
2876fe57b42Smillert 			break;
2886fe57b42Smillert 
289508086e9Smillert 		case 'M': {
290508086e9Smillert 			sig_t opipe = signal(SIGPIPE, SIG_IGN);
29108f8e31fSotto 			char *pager, *cmd = NULL;
292e7936562Sderaadt 			extern const u_char manpage[];
29308f8e31fSotto 			extern const int manpage_sz;
2945d12b01bSderaadt 
295489bd112Spjanzen 			if ((pager = getenv("PAGER")) == NULL || *pager == '\0')
296508086e9Smillert 				pager = _PATH_LESS;
29708f8e31fSotto 
29808f8e31fSotto 			if (asprintf(&cmd, "gunzip -qc|%s", pager) != -1 &&
29908f8e31fSotto 			    (fp = popen(cmd, "w")) != NULL) {
30008f8e31fSotto 				(void) fwrite(manpage, manpage_sz, 1, fp);
3015d12b01bSderaadt 				pclose(fp);
302508086e9Smillert 			} else
303508086e9Smillert 				warn("unable to execute %s", pager);
304508086e9Smillert 
30508f8e31fSotto 			free(cmd);
306508086e9Smillert 			(void)signal(SIGPIPE, opipe);
3075d12b01bSderaadt 			break;
308508086e9Smillert 		}
3095d12b01bSderaadt 
3106fe57b42Smillert 		case 'q':
31169220492Smillert 			if (donothing) {
31269220492Smillert 				puts("In no change mode, not writing label.");
31369220492Smillert 				return(1);
31469220492Smillert 			}
315bd6726faSmillert 			/* Save mountpoint info if there is any. */
316bd6726faSmillert 			if (mountpoints != NULL)
317bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
31871bba4ecSkrw 			/*
31971bba4ecSkrw 			 * If we didn't manufacture a new default label and
32071bba4ecSkrw 			 * didn't change the label read from disk, there is no
32171bba4ecSkrw 			 * need to do anything before exiting.
32271bba4ecSkrw 			 */
32371bba4ecSkrw 			if (!dflag && memcmp(lp, &label, sizeof(label)) == 0) {
324bd6726faSmillert 				puts("No label changes.");
3256fe57b42Smillert 				return(1);
3266fe57b42Smillert 			}
3276fe57b42Smillert 			do {
328d0e67762Smillert 				arg = getstring("Write new label?",
329d0e67762Smillert 				    "Write the modified label to disk?",
330d0e67762Smillert 				    "y");
33196a888c6Smillert 			} while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n');
33296a888c6Smillert 			if (arg && tolower(*arg) == 'y') {
333d0e67762Smillert 				if (writelabel(f, bootarea, &label) == 0) {
3346fe57b42Smillert 					*lp = label;
3356fe57b42Smillert 					return(0);
3366fe57b42Smillert 				}
337d0e67762Smillert 				warnx("unable to write label");
338d0e67762Smillert 			}
3396fe57b42Smillert 			return(1);
3406fe57b42Smillert 			/* NOTREACHED */
3416fe57b42Smillert 			break;
3426fe57b42Smillert 
34325f9c360Skrw 		case 'r': {
34425f9c360Skrw 			struct diskchunk *chunks;
34525f9c360Skrw 			int i;
3469fdcb4d6Skrw 			/* Display free space. */
34725f9c360Skrw 			chunks = free_chunks(&label);
34825f9c360Skrw 			for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0;
34925f9c360Skrw 			    i++)
35025f9c360Skrw 				fprintf(stderr, "Free sectors: %16llu - %16llu "
35125f9c360Skrw 				    "(%16llu)\n",
35225f9c360Skrw 			    	    chunks[i].start, chunks[i].stop - 1,
35325f9c360Skrw 			   	    chunks[i].stop - chunks[i].start);
35425f9c360Skrw 			fprintf(stderr, "Total free sectors: %llu.\n",
3559fdcb4d6Skrw 			    editor_countfree(&label));
356c0bdc608Smillert 		    	break;
35725f9c360Skrw 		}
358c0bdc608Smillert 
3596fe57b42Smillert 		case 's':
3606fe57b42Smillert 			if (arg == NULL) {
361c33fcabaSmillert 				arg = getstring("Filename",
3626fe57b42Smillert 				    "Name of the file to save label into.",
3636fe57b42Smillert 				    NULL);
36496a888c6Smillert 				if (arg == NULL && *arg == '\0')
3656fe57b42Smillert 					break;
3666fe57b42Smillert 			}
3676fe57b42Smillert 			if ((fp = fopen(arg, "w")) == NULL) {
3686fe57b42Smillert 				warn("cannot open %s", arg);
3696fe57b42Smillert 			} else {
3705b19a791Sotto 				display(fp, &label, NULL, 0, 0, 0);
3716fe57b42Smillert 				(void)fclose(fp);
3726fe57b42Smillert 			}
3736fe57b42Smillert 			break;
3746fe57b42Smillert 
3756fe57b42Smillert 		case 'u':
376bd6726faSmillert 			if (memcmp(&label, &lastlabel, sizeof(label)) == 0 &&
377bd6726faSmillert 			    mountpoints != NULL &&
378bd6726faSmillert 			    mpequal(mountpoints, omountpoints)) {
3796fe57b42Smillert 				puts("Nothing to undo!");
3806fe57b42Smillert 			} else {
3816fe57b42Smillert 				tmplabel = label;
3826fe57b42Smillert 				label = lastlabel;
3836fe57b42Smillert 				lastlabel = tmplabel;
384bd6726faSmillert 				/* Restore mountpoints */
385bd6726faSmillert 				if (mountpoints != NULL)
386bd6726faSmillert 					mpcopy(mountpoints, omountpoints);
3876fe57b42Smillert 				puts("Last change undone.");
3886fe57b42Smillert 			}
3896fe57b42Smillert 			break;
3906fe57b42Smillert 
391040947cfSmillert 		case 'w':
392bd6726faSmillert 			if (donothing)  {
393040947cfSmillert 				puts("In no change mode, not writing label.");
394bd6726faSmillert 				break;
395bd6726faSmillert 			}
396bd6726faSmillert 			/* Save mountpoint info if there is any. */
397bd6726faSmillert 			if (mountpoints != NULL)
398bd6726faSmillert 				mpsave(&label, mountpoints, dev, fstabfile);
39941f684b9Skrw 			/* Write label to disk. */
40041f684b9Skrw 			if (writelabel(f, bootarea, &label) != 0)
401040947cfSmillert 				warnx("unable to write label");
40271bba4ecSkrw 			else {
40371bba4ecSkrw 				dflag = 0;
4045af08e9cSmillert 				*lp = label;
40571bba4ecSkrw 			}
406040947cfSmillert 			break;
407040947cfSmillert 
4082d8451b0Smillert 		case 'X':
4092d8451b0Smillert 			expert = !expert;
4102d8451b0Smillert 			printf("%s expert mode\n", expert ? "Entering" :
4112d8451b0Smillert 			    "Exiting");
4122d8451b0Smillert 			break;
4132d8451b0Smillert 
4146fe57b42Smillert 		case 'x':
4156fe57b42Smillert 			return(1);
4166fe57b42Smillert 			break;
4176fe57b42Smillert 
4189afbe9eeSmillert 		case 'z':
419cdd7eb76Smillert 			tmplabel = lastlabel;
420cdd7eb76Smillert 			lastlabel = label;
4219fdcb4d6Skrw 			zero_partitions(&label);
4226fe57b42Smillert 			break;
4236fe57b42Smillert 
4249afbe9eeSmillert 		case '\n':
4256fe57b42Smillert 			break;
4266fe57b42Smillert 
4276fe57b42Smillert 		default:
4286fe57b42Smillert 			printf("Unknown option: %c ('?' for help)\n", *cmd);
4296fe57b42Smillert 			break;
4306fe57b42Smillert 		}
4316fe57b42Smillert 	}
4326fe57b42Smillert }
4336fe57b42Smillert 
4346fe57b42Smillert /*
4356fe57b42Smillert  * Add a new partition.
4366fe57b42Smillert  */
4376fe57b42Smillert void
4389fdcb4d6Skrw editor_add(struct disklabel *lp, char **mp, char *p)
4396fe57b42Smillert {
44096a888c6Smillert 	struct partition *pp;
44196a888c6Smillert 	struct diskchunk *chunks;
4425caa08b2Skrw 	char buf[2];
4436fe57b42Smillert 	int i, partno;
444f8ab7229Schl 	u_int64_t freesectors, new_offset, new_size;
4459fdcb4d6Skrw 
4469fdcb4d6Skrw 	freesectors = editor_countfree(lp);
4476fe57b42Smillert 
4486fe57b42Smillert 	/* XXX - prompt user to steal space from another partition instead */
449fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
4509fdcb4d6Skrw 	if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) {
451fc1a4cc6Sderaadt 		fputs("No space left, you need to shrink a partition "
452fc1a4cc6Sderaadt 		    "(need at least one full cylinder)\n",
453fc1a4cc6Sderaadt 		    stderr);
454fc1a4cc6Sderaadt 		return;
455fc1a4cc6Sderaadt 	}
4568390cf28Smillert #endif
4579fdcb4d6Skrw 	if (freesectors == 0) {
4586fe57b42Smillert 		fputs("No space left, you need to shrink a partition\n",
4596fe57b42Smillert 		    stderr);
4606fe57b42Smillert 		return;
4616fe57b42Smillert 	}
4626fe57b42Smillert 
4635caa08b2Skrw 	if (p == NULL) {
4645caa08b2Skrw 		/*
4655caa08b2Skrw 		 * Use the first unused partition that is not 'c' as the
4665caa08b2Skrw 		 * default partition in the prompt string.
4675caa08b2Skrw 		 */
4685caa08b2Skrw 		pp = &lp->d_partitions[0];
4695caa08b2Skrw 		buf[0] = buf[1] = '\0';
4705caa08b2Skrw 		for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) {
4715caa08b2Skrw 			if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) {
4725caa08b2Skrw 				buf[0] = partno + 'a';
4735caa08b2Skrw 				p = &buf[0];
4746fe57b42Smillert 				break;
4756fe57b42Smillert 			}
4765caa08b2Skrw 		}
477c33fcabaSmillert 		p = getstring("partition",
4786fe57b42Smillert 		    "The letter of the new partition, a - p.", p);
4796fe57b42Smillert 	}
4805caa08b2Skrw 	if (p == NULL) {
4815caa08b2Skrw 		fputs("Command aborted\n", stderr);
4825caa08b2Skrw 		return;
4835caa08b2Skrw 	}
4845caa08b2Skrw 	partno = p[0] - 'a';
4855caa08b2Skrw 	if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) {
4865caa08b2Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
4875caa08b2Skrw 		    "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1);
4885caa08b2Skrw 		return;
4895caa08b2Skrw 	}
4905caa08b2Skrw 	pp = &lp->d_partitions[partno];
4915caa08b2Skrw 
4925caa08b2Skrw 	if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) {
4935caa08b2Skrw 		fprintf(stderr, "Partition '%c' exists.  Delete it first.\n",
4945caa08b2Skrw 		    p[0]);
4955caa08b2Skrw 		return;
4966fe57b42Smillert 	}
49796a888c6Smillert 
498caf41f96Skrw 	/*
499caf41f96Skrw 	 * Increase d_npartitions if necessary. Ensure all new partitions are
500caf41f96Skrw 	 * zero'ed to avoid inadvertant overlaps.
501caf41f96Skrw 	 */
502caf41f96Skrw 	for(; lp->d_npartitions <= partno; lp->d_npartitions++)
503caf41f96Skrw 		memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp));
50496a888c6Smillert 
50589f4601dSkrw 	/* Make sure selected partition is zero'd too. */
50689f4601dSkrw 	memset(pp, 0, sizeof(*pp));
50715c15d8aSkrw 	chunks = free_chunks(lp);
50815c15d8aSkrw 
50915c15d8aSkrw 	/*
51015c15d8aSkrw 	 * Since we know there's free space, there must be at least one
51115c15d8aSkrw 	 * chunk. So find the largest chunk and assume we want to add the
51215c15d8aSkrw 	 * partition in that free space.
51315c15d8aSkrw 	 */
51415c15d8aSkrw 	new_size = new_offset = 0;
51515c15d8aSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
51615c15d8aSkrw 		if (chunks[i].stop - chunks[i].start > new_size) {
51715c15d8aSkrw 		    new_size = chunks[i].stop - chunks[i].start;
51815c15d8aSkrw 		    new_offset = chunks[i].start;
51915c15d8aSkrw 		}
52015c15d8aSkrw 	}
5211e0ad43cSotto 	DL_SETPSIZE(pp, new_size);
5221e0ad43cSotto 	DL_SETPOFFSET(pp, new_offset);
52396a888c6Smillert 	pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS;
5244a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__)
525d98d4df7Stedu 	/* can't boot from > 8k boot blocks */
526ddfcbf38Sotto 	pp->p_fragblock =
527ddfcbf38Sotto 	    DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : 2048, 8);
528d98d4df7Stedu #else
529ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
530d98d4df7Stedu #endif
5319b972314Skrw 	pp->p_cpg = 1;
53296a888c6Smillert 
533a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
534a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
535a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
536a4c87e64Skrw 	    get_mp(lp, mp, partno) == 0 &&
537a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
538a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
53996a888c6Smillert 		return;
54096a888c6Smillert 
541a4c87e64Skrw 	/* Bailed out at some point, so effectively delete the partition. */
542a4c87e64Skrw 	DL_SETPSIZE(pp, 0);
5436fe57b42Smillert }
5446fe57b42Smillert 
5456fe57b42Smillert /*
546bd6726faSmillert  * Set the mountpoint of an existing partition ('name').
547bd6726faSmillert  */
548bd6726faSmillert void
5498809fabbSderaadt editor_name(struct disklabel *lp, char **mp, char *p)
550bd6726faSmillert {
551bd6726faSmillert 	struct partition *pp;
552bd6726faSmillert 	int partno;
553bd6726faSmillert 
554bd6726faSmillert 	/* Change which partition? */
555bd6726faSmillert 	if (p == NULL) {
556c33fcabaSmillert 		p = getstring("partition to name",
557bd6726faSmillert 		    "The letter of the partition to name, a - p.", NULL);
558bd6726faSmillert 	}
559bd6726faSmillert 	if (p == NULL) {
560bd6726faSmillert 		fputs("Command aborted\n", stderr);
561bd6726faSmillert 		return;
562bd6726faSmillert 	}
563bd6726faSmillert 	partno = p[0] - 'a';
5646c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
5656c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
5666c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
567bd6726faSmillert 		return;
56866df1f0cSkrw 	}
56966df1f0cSkrw 	pp = &lp->d_partitions[partno];
57066df1f0cSkrw 
57166df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
57266df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
573bd6726faSmillert 		return;
574bd6726faSmillert 	}
575bd6726faSmillert 
576bd6726faSmillert 	/* Not all fstypes can be named */
577bd6726faSmillert 	if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP ||
578bd387921Stodd 	    pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER ||
579bd387921Stodd 	    pp->p_fstype == FS_RAID) {
580bd6726faSmillert 		fprintf(stderr, "You cannot name a filesystem of type %s.\n",
581baa55472Smillert 		    fstypenames[lp->d_partitions[partno].p_fstype]);
582bd6726faSmillert 		return;
583bd6726faSmillert 	}
584bd6726faSmillert 
585ddaff619Smillert 	get_mp(lp, mp, partno);
586bd6726faSmillert }
587bd6726faSmillert 
588bd6726faSmillert /*
5896fe57b42Smillert  * Change an existing partition.
5906fe57b42Smillert  */
5916fe57b42Smillert void
5929fdcb4d6Skrw editor_modify(struct disklabel *lp, char **mp, char *p)
5936fe57b42Smillert {
5946fe57b42Smillert 	struct partition origpart, *pp;
595f8ab7229Schl 	int partno;
5966fe57b42Smillert 
5976fe57b42Smillert 	/* Change which partition? */
5986fe57b42Smillert 	if (p == NULL) {
599c33fcabaSmillert 		p = getstring("partition to modify",
6006fe57b42Smillert 		    "The letter of the partition to modify, a - p.", NULL);
6016fe57b42Smillert 	}
60296a888c6Smillert 	if (p == NULL) {
60396a888c6Smillert 		fputs("Command aborted\n", stderr);
60496a888c6Smillert 		return;
60596a888c6Smillert 	}
6066fe57b42Smillert 	partno = p[0] - 'a';
6076c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
6086c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
6096c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
6106fe57b42Smillert 		return;
61166df1f0cSkrw 	}
61266df1f0cSkrw 	pp = &lp->d_partitions[partno];
61366df1f0cSkrw 
61466df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
61566df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
6166fe57b42Smillert 		return;
6176fe57b42Smillert 	}
6186fe57b42Smillert 
61966df1f0cSkrw 	origpart = *pp;
62066df1f0cSkrw 
621a4c87e64Skrw 	if (get_offset(lp, partno) == 0 &&
622a4c87e64Skrw 	    get_size(lp, partno) == 0   &&
623a4c87e64Skrw 	    get_fstype(lp, partno) == 0 &&
624a4c87e64Skrw 	    get_mp(lp, mp, partno) == 0 &&
625a4c87e64Skrw 	    get_fsize(lp, partno) == 0  &&
626a4c87e64Skrw 	    get_bsize(lp, partno) == 0)
62796a888c6Smillert 		return;
6286fe57b42Smillert 
629a4c87e64Skrw 	/* Bailed out at some point, so undo any changes. */
630a4c87e64Skrw 	*pp = origpart;
6316fe57b42Smillert }
6326fe57b42Smillert 
6336fe57b42Smillert /*
6346fe57b42Smillert  * Delete an existing partition.
6356fe57b42Smillert  */
6366fe57b42Smillert void
6379fdcb4d6Skrw editor_delete(struct disklabel *lp, char **mp, char *p)
6386fe57b42Smillert {
63966df1f0cSkrw 	struct partition *pp;
640135c90d1Skrw 	int partno;
6416fe57b42Smillert 
6426fe57b42Smillert 	if (p == NULL) {
643c33fcabaSmillert 		p = getstring("partition to delete",
644945ae268Smillert 		    "The letter of the partition to delete, a - p, or '*'.",
645945ae268Smillert 		    NULL);
6466fe57b42Smillert 	}
64796a888c6Smillert 	if (p == NULL) {
64896a888c6Smillert 		fputs("Command aborted\n", stderr);
64996a888c6Smillert 		return;
65096a888c6Smillert 	}
651945ae268Smillert 	if (p[0] == '*') {
6529fdcb4d6Skrw 		zero_partitions(lp);
653945ae268Smillert 		return;
654945ae268Smillert 	}
655135c90d1Skrw 	partno = p[0] - 'a';
656135c90d1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
6576c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
6586c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
65933262abfSmiod 		return;
66066df1f0cSkrw 	}
661135c90d1Skrw 	pp = &lp->d_partitions[partno];
66266df1f0cSkrw 
66366df1f0cSkrw 	if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) {
66466df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
66533262abfSmiod 		return;
66666df1f0cSkrw 	}
66766df1f0cSkrw 
6686fe57b42Smillert 	/* Really delete it (as opposed to just setting to "unused") */
669135c90d1Skrw 	memset(pp, 0, sizeof(*pp));
670135c90d1Skrw 
671135c90d1Skrw 	if (mp != NULL && mp[partno] != NULL) {
672135c90d1Skrw 		free(mp[partno]);
673135c90d1Skrw 		mp[partno] = NULL;
674bd6726faSmillert 	}
6756fe57b42Smillert }
6766fe57b42Smillert 
6776fe57b42Smillert /*
6786fe57b42Smillert  * Change the size of an existing partition.
6796fe57b42Smillert  */
6806fe57b42Smillert void
6819fdcb4d6Skrw editor_change(struct disklabel *lp, char *p)
6826fe57b42Smillert {
6834b9a3bdaSmillert 	struct partition *pp;
68466df1f0cSkrw 	int partno;
6856fe57b42Smillert 
6866fe57b42Smillert 	if (p == NULL) {
687c33fcabaSmillert 		p = getstring("partition to change size",
6886fe57b42Smillert 		    "The letter of the partition to change size, a - p.", NULL);
6896fe57b42Smillert 	}
69096a888c6Smillert 	if (p == NULL) {
69196a888c6Smillert 		fputs("Command aborted\n", stderr);
69296a888c6Smillert 		return;
69396a888c6Smillert 	}
6946fe57b42Smillert 	partno = p[0] - 'a';
6956c729bd1Skrw 	if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) {
6966c729bd1Skrw 		fprintf(stderr, "Partition must be between 'a' and '%c' "
6976c729bd1Skrw 		    "(excluding 'c').\n", 'a' + lp->d_npartitions - 1);
6986fe57b42Smillert 		return;
6996fe57b42Smillert 	}
7004b9a3bdaSmillert 	pp = &lp->d_partitions[partno];
7016fe57b42Smillert 
70266df1f0cSkrw 	if (DL_GETPSIZE(pp) == 0) {
70366df1f0cSkrw 		fprintf(stderr, "Partition '%c' is not in use.\n", p[0]);
70466df1f0cSkrw 		return;
70566df1f0cSkrw 	}
70666df1f0cSkrw 
70714192793Skrw 	printf("Partition %c is currently %llu sectors in size, and can have "
70814192793Skrw 	    "a maximum\nsize of %llu sectors.\n",
70914192793Skrw 	    p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno));
7107da73705Skrw 
71159ccf790Skrw 	/* Get new size */
7129fdcb4d6Skrw 	get_size(lp, partno);
7136fe57b42Smillert }
7146fe57b42Smillert 
7156fe57b42Smillert /*
7166fe57b42Smillert  * Sort the partitions based on starting offset.
7176fe57b42Smillert  * This assumes there can be no overlap.
7186fe57b42Smillert  */
7196fe57b42Smillert int
7208809fabbSderaadt partition_cmp(const void *e1, const void *e2)
7216fe57b42Smillert {
7226fe57b42Smillert 	struct partition *p1 = *(struct partition **)e1;
7236fe57b42Smillert 	struct partition *p2 = *(struct partition **)e2;
7241e0ad43cSotto 	u_int64_t o1 = DL_GETPOFFSET(p1);
7251e0ad43cSotto 	u_int64_t o2 = DL_GETPOFFSET(p2);
7266fe57b42Smillert 
7271e0ad43cSotto 	if (o1 < o2)
728651d5bd9Sotto 		return -1;
7291e0ad43cSotto 	else if (o1 > o2)
730651d5bd9Sotto 		return 1;
731651d5bd9Sotto 	else
732651d5bd9Sotto 		return 0;
7336fe57b42Smillert }
7346fe57b42Smillert 
7356fe57b42Smillert char *
7368809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval)
7376fe57b42Smillert {
7386fe57b42Smillert 	static char buf[BUFSIZ];
7396fe57b42Smillert 	int n;
7406fe57b42Smillert 
7416fe57b42Smillert 	buf[0] = '\0';
7426fe57b42Smillert 	do {
7436fe57b42Smillert 		printf("%s: [%s] ", prompt, oval ? oval : "");
7446e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
745260513deSmillert 			buf[0] = '\0';
74696a888c6Smillert 			if (feof(stdin)) {
74724c6582eSmillert 				clearerr(stdin);
74896a888c6Smillert 				putchar('\n');
74996a888c6Smillert 				return(NULL);
75096a888c6Smillert 			}
7516e0becc5Smillert 		}
7526fe57b42Smillert 		n = strlen(buf);
7536fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
7546fe57b42Smillert 			buf[--n] = '\0';
7556fe57b42Smillert 		if (buf[0] == '?')
7566fe57b42Smillert 			puts(helpstring);
7574fb6ab7cSmillert 		else if (oval != NULL && buf[0] == '\0')
7584fb6ab7cSmillert 			strlcpy(buf, oval, sizeof(buf));
7596fe57b42Smillert 	} while (buf[0] == '?');
7606fe57b42Smillert 
7616fe57b42Smillert 	return(&buf[0]);
7626fe57b42Smillert }
7636fe57b42Smillert 
7646fe57b42Smillert /*
7651e0ad43cSotto  * Returns ULLONG_MAX on error
76624a2c1a4Smillert  * Usually only called by helper functions.
7676fe57b42Smillert  */
7681e0ad43cSotto u_int64_t
7698809fabbSderaadt getuint(struct disklabel *lp, int partno, char *prompt, char *helpstring,
7701e0ad43cSotto     u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags)
7716fe57b42Smillert {
7726fe57b42Smillert 	char buf[BUFSIZ], *endptr, *p, operator = '\0';
7731e0ad43cSotto 	u_int64_t rval = oval;
7746fe57b42Smillert 	size_t n;
7756fe57b42Smillert 	int mult = 1;
77614cc915fSmillert 	double d, percent = 1.0;
7776fe57b42Smillert 
7784b9a3bdaSmillert 	/* We only care about the remainder */
7794b9a3bdaSmillert 	offset = offset % lp->d_secpercyl;
7804b9a3bdaSmillert 
7816fe57b42Smillert 	buf[0] = '\0';
7826fe57b42Smillert 	do {
7831e0ad43cSotto 		printf("%s: [%llu] ", prompt, oval);
7846e0becc5Smillert 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
7856e0becc5Smillert 			buf[0] = '\0';
78696a888c6Smillert 			if (feof(stdin)) {
78724c6582eSmillert 				clearerr(stdin);
78896a888c6Smillert 				putchar('\n');
7891e0ad43cSotto 				return(ULLONG_MAX - 1);
79096a888c6Smillert 			}
7916e0becc5Smillert 		}
7926fe57b42Smillert 		n = strlen(buf);
7936fe57b42Smillert 		if (n > 0 && buf[n-1] == '\n')
7946fe57b42Smillert 			buf[--n] = '\0';
7956fe57b42Smillert 		if (buf[0] == '?')
7966fe57b42Smillert 			puts(helpstring);
7976fe57b42Smillert 	} while (buf[0] == '?');
7986fe57b42Smillert 
7996fe57b42Smillert 	if (buf[0] == '*' && buf[1] == '\0') {
8006fe57b42Smillert 		rval = maxval;
8016fe57b42Smillert 	} else {
8026fe57b42Smillert 		/* deal with units */
8036fe57b42Smillert 		if (buf[0] != '\0' && n > 0) {
8046fe57b42Smillert 			if ((flags & DO_CONVERSIONS)) {
80596a888c6Smillert 				switch (tolower(buf[n-1])) {
8066fe57b42Smillert 
8076fe57b42Smillert 				case 'c':
8086fe57b42Smillert 					mult = lp->d_secpercyl;
8096fe57b42Smillert 					buf[--n] = '\0';
8106fe57b42Smillert 					break;
8116fe57b42Smillert 				case 'b':
8126fe57b42Smillert 					mult = -lp->d_secsize;
8136fe57b42Smillert 					buf[--n] = '\0';
8146fe57b42Smillert 					break;
8156fe57b42Smillert 				case 'k':
81650c0f47aSkrw 					if (lp->d_secsize > 1024)
81750c0f47aSkrw 						mult = -lp->d_secsize / 1024;
81850c0f47aSkrw 					else
8196fe57b42Smillert 						mult = 1024 / lp->d_secsize;
8206fe57b42Smillert 					buf[--n] = '\0';
8216fe57b42Smillert 					break;
8226fe57b42Smillert 				case 'm':
8236fe57b42Smillert 					mult = 1048576 / lp->d_secsize;
8246fe57b42Smillert 					buf[--n] = '\0';
8256fe57b42Smillert 					break;
8261a51a1eeSmillert 				case 'g':
8271a51a1eeSmillert 					mult = 1073741824 / lp->d_secsize;
8281a51a1eeSmillert 					buf[--n] = '\0';
8291a51a1eeSmillert 					break;
83014cc915fSmillert 				case '%':
83114cc915fSmillert 					buf[--n] = '\0';
83214cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
8331e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
8341e0ad43cSotto 					    DL_GETDSIZE(lp));
83514cc915fSmillert 					break;
83614cc915fSmillert 				case '&':
83714cc915fSmillert 					buf[--n] = '\0';
83814cc915fSmillert 					percent = strtod(buf, NULL) / 100.0;
8391e0ad43cSotto 					snprintf(buf, sizeof(buf), "%lld",
84014cc915fSmillert 					    maxval);
84114cc915fSmillert 					break;
8426fe57b42Smillert 				}
84396a888c6Smillert 			}
8446fe57b42Smillert 
8456fe57b42Smillert 			/* Did they give us an operator? */
8466fe57b42Smillert 			p = &buf[0];
8476fe57b42Smillert 			if (*p == '+' || *p == '-')
8486fe57b42Smillert 				operator = *p++;
8496fe57b42Smillert 
8506fe57b42Smillert 			endptr = p;
85196a888c6Smillert 			errno = 0;
85296a888c6Smillert 			d = strtod(p, &endptr);
85396a888c6Smillert 			if (errno == ERANGE)
8541e0ad43cSotto 				rval = ULLONG_MAX;	/* too big/small */
85596a888c6Smillert 			else if (*endptr != '\0') {
8566fe57b42Smillert 				errno = EINVAL;		/* non-numbers in str */
8571e0ad43cSotto 				rval = ULLONG_MAX;
8586fe57b42Smillert 			} else {
85996a888c6Smillert 				/* XXX - should check for overflow */
86096a888c6Smillert 				if (mult > 0)
86114cc915fSmillert 					rval = d * mult * percent;
86296a888c6Smillert 				else
86396a888c6Smillert 					/* Negative mult means divide (fancy) */
86414cc915fSmillert 					rval = d / (-mult) * percent;
8656fe57b42Smillert 
86696a888c6Smillert 				/* Apply the operator */
8676fe57b42Smillert 				if (operator == '+')
8686fe57b42Smillert 					rval += oval;
8696fe57b42Smillert 				else if (operator == '-')
8706fe57b42Smillert 					rval = oval - rval;
8716fe57b42Smillert 			}
8726fe57b42Smillert 		}
8736fe57b42Smillert 	}
8748390cf28Smillert 	if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) {
87596a888c6Smillert 		/* Round to nearest cylinder unless given in sectors */
8768390cf28Smillert 		if (
877fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK
878fc1a4cc6Sderaadt 		    ((lp->d_flags & D_VENDOR) || mult != 1) &&
879fc1a4cc6Sderaadt #else
8808390cf28Smillert 		    mult != 1 &&
881dbffb156Smillert #endif
8828390cf28Smillert 		    (rval + offset) % lp->d_secpercyl != 0) {
8831e0ad43cSotto 			u_int64_t cyls;
884dbffb156Smillert 
8858390cf28Smillert 			/* Round to higher cylinder but no more than maxval */
8868390cf28Smillert 			cyls = (rval / lp->d_secpercyl) + 1;
8878390cf28Smillert 			if ((cyls * lp->d_secpercyl) - offset > maxval)
888dbffb156Smillert 				cyls--;
8894b9a3bdaSmillert 			rval = (cyls * lp->d_secpercyl) - offset;
8908390cf28Smillert 			printf("Rounding to cylinder: %llu\n", rval);
8916fe57b42Smillert 		}
8924b9a3bdaSmillert 	}
8936fe57b42Smillert 
8946fe57b42Smillert 	return(rval);
8956fe57b42Smillert }
8966fe57b42Smillert 
8976fe57b42Smillert /*
8981f0f871dSkrw  * Check for partition overlap in lp and prompt the user to resolve the overlap
8991f0f871dSkrw  * if any is found.  Returns 1 if unable to resolve, else 0.
9006fe57b42Smillert  */
9016fe57b42Smillert int
9021f0f871dSkrw has_overlap(struct disklabel *lp)
9036fe57b42Smillert {
9046fe57b42Smillert 	struct partition **spp;
9056fe57b42Smillert 	u_int16_t npartitions;
906e6aa8bafSmillert 	int c, i, j;
907e6aa8bafSmillert 	char buf[BUFSIZ];
9086fe57b42Smillert 
909a7e61405Smillert 	/* Get a sorted list of the partitions */
910a7e61405Smillert 	spp = sort_partitions(lp, &npartitions);
9116fe57b42Smillert 
912*d18c2a43Skrw 	if (npartitions < RAW_PART)
9136fe57b42Smillert 		return(0);			/* nothing to do */
9146fe57b42Smillert 
9156fe57b42Smillert 	/* Now that we have things sorted by starting sector check overlap */
9166fe57b42Smillert 	for (i = 0; i < npartitions; i++) {
9176fe57b42Smillert 		for (j = i + 1; j < npartitions; j++) {
9186fe57b42Smillert 			/* `if last_sec_in_part + 1 > first_sec_in_next_part' */
9191e0ad43cSotto 			if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) {
9206fe57b42Smillert 				/* Overlap!  Convert to real part numbers. */
9216fe57b42Smillert 				i = ((char *)spp[i] - (char *)lp->d_partitions)
9226fe57b42Smillert 				    / sizeof(**spp);
9236fe57b42Smillert 				j = ((char *)spp[j] - (char *)lp->d_partitions)
9246fe57b42Smillert 				    / sizeof(**spp);
9256fe57b42Smillert 				printf("\nError, partitions %c and %c overlap:\n",
9266fe57b42Smillert 				    'a' + i, 'a' + j);
927366bf641Skrw 				printf("#    %16.16s %16.16s  fstype "
928651d5bd9Sotto 				    "[fsize bsize  cpg]\n", "size", "offset");
929f21a098bSotto 				display_partition(stdout, lp, NULL, i, 0);
930f21a098bSotto 				display_partition(stdout, lp, NULL, j, 0);
9316fe57b42Smillert 
932e6aa8bafSmillert 				/* Get partition to disable or ^D */
933e6aa8bafSmillert 				do {
934616cd1c4Smillert 					printf("Disable which one? (^D to abort) [%c %c] ",
9356fe57b42Smillert 					    'a' + i, 'a' + j);
936e6aa8bafSmillert 					buf[0] = '\0';
937616cd1c4Smillert 					if (!fgets(buf, sizeof(buf), stdin)) {
938616cd1c4Smillert 						putchar('\n');
939e6aa8bafSmillert 						return(1);	/* ^D */
940616cd1c4Smillert 					}
941e6aa8bafSmillert 					c = buf[0] - 'a';
942e6aa8bafSmillert 				} while (buf[1] != '\n' && buf[1] != '\0' &&
943e6aa8bafSmillert 				    c != i && c != j);
944e6aa8bafSmillert 
945e6aa8bafSmillert 				/* Mark the selected one as unused */
9466fe57b42Smillert 				lp->d_partitions[c].p_fstype = FS_UNUSED;
9471f0f871dSkrw 				return (has_overlap(lp));
9486fe57b42Smillert 			}
9496fe57b42Smillert 		}
9506fe57b42Smillert 	}
951f0b4d0a9Smillert 
952e6aa8bafSmillert 	return(0);
9536fe57b42Smillert }
9546fe57b42Smillert 
9556fe57b42Smillert void
9569fdcb4d6Skrw edit_parms(struct disklabel *lp)
9576fe57b42Smillert {
9586fe57b42Smillert 	char *p;
9599fdcb4d6Skrw 	u_int64_t freesectors, ui;
96096a888c6Smillert 	struct disklabel oldlabel = *lp;
9616fe57b42Smillert 
962ea37abd3Sderaadt 	printf("Changing device parameters for %s:\n", specname);
9636fe57b42Smillert 
9640f820bbbSmillert 	/* disk type */
9650f820bbbSmillert 	for (;;) {
966c33fcabaSmillert 		p = getstring("disk type",
96741282a2aSmillert 		    "What kind of disk is this?  Usually SCSI, ESDI, ST506, or "
96841282a2aSmillert 		    "floppy (use ESDI for IDE).", dktypenames[lp->d_type]);
96996a888c6Smillert 		if (p == NULL) {
97096a888c6Smillert 			fputs("Command aborted\n", stderr);
97196a888c6Smillert 			return;
97296a888c6Smillert 		}
97341282a2aSmillert 		if (strcasecmp(p, "IDE") == 0)
97441282a2aSmillert 			ui = DTYPE_ESDI;
97541282a2aSmillert 		else
97641282a2aSmillert 			for (ui = 1; ui < DKMAXTYPES &&
97741282a2aSmillert 			    strcasecmp(p, dktypenames[ui]); ui++)
9780f820bbbSmillert 				;
9790f820bbbSmillert 		if (ui < DKMAXTYPES) {
9800f820bbbSmillert 			break;
9810f820bbbSmillert 		} else {
9820f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", p);
9830f820bbbSmillert 			fputs("Valid types are: ", stdout);
9840f820bbbSmillert 			for (ui = 1; ui < DKMAXTYPES; ui++) {
9850f820bbbSmillert 				printf("\"%s\"", dktypenames[ui]);
9860f820bbbSmillert 				if (ui < DKMAXTYPES - 1)
9870f820bbbSmillert 					fputs(", ", stdout);
9880f820bbbSmillert 			}
9890f820bbbSmillert 			putchar('\n');
9900f820bbbSmillert 		}
9910f820bbbSmillert 	}
9920f820bbbSmillert 	lp->d_type = ui;
9930f820bbbSmillert 
9946fe57b42Smillert 	/* pack/label id */
995c33fcabaSmillert 	p = getstring("label name",
9966fe57b42Smillert 	    "15 char string that describes this label, usually the disk name.",
9976fe57b42Smillert 	    lp->d_packname);
99896a888c6Smillert 	if (p == NULL) {
99996a888c6Smillert 		fputs("Command aborted\n", stderr);
100096a888c6Smillert 		*lp = oldlabel;		/* undo damage */
100196a888c6Smillert 		return;
100296a888c6Smillert 	}
10034fb6ab7cSmillert 	strncpy(lp->d_packname, p, sizeof(lp->d_packname));	/* checked */
10046fe57b42Smillert 
10056fe57b42Smillert 	/* sectors/track */
10066fe57b42Smillert 	for (;;) {
10076fe57b42Smillert 		ui = getuint(lp, 0, "sectors/track",
10086fe57b42Smillert 		    "The Numer of sectors per track.", lp->d_nsectors,
10094b9a3bdaSmillert 		    lp->d_nsectors, 0, 0);
10101e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
101196a888c6Smillert 			fputs("Command aborted\n", stderr);
101296a888c6Smillert 			*lp = oldlabel;		/* undo damage */
101396a888c6Smillert 			return;
10141e0ad43cSotto 		} if (ui == ULLONG_MAX)
10156fe57b42Smillert 			fputs("Invalid entry\n", stderr);
10166fe57b42Smillert 		else
10176fe57b42Smillert 			break;
10186fe57b42Smillert 	}
10196fe57b42Smillert 	lp->d_nsectors = ui;
10206fe57b42Smillert 
10216fe57b42Smillert 	/* tracks/cylinder */
10226fe57b42Smillert 	for (;;) {
10236fe57b42Smillert 		ui = getuint(lp, 0, "tracks/cylinder",
10246fe57b42Smillert 		    "The number of tracks per cylinder.", lp->d_ntracks,
10254b9a3bdaSmillert 		    lp->d_ntracks, 0, 0);
10261e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
102796a888c6Smillert 			fputs("Command aborted\n", stderr);
102896a888c6Smillert 			*lp = oldlabel;		/* undo damage */
102996a888c6Smillert 			return;
10301e0ad43cSotto 		} else if (ui == ULLONG_MAX)
10316fe57b42Smillert 			fputs("Invalid entry\n", stderr);
10326fe57b42Smillert 		else
10336fe57b42Smillert 			break;
10346fe57b42Smillert 	}
10356fe57b42Smillert 	lp->d_ntracks = ui;
10366fe57b42Smillert 
10376fe57b42Smillert 	/* sectors/cylinder */
1038148b6188Smillert 	for (;;) {
1039148b6188Smillert 		ui = getuint(lp, 0, "sectors/cylinder",
1040148b6188Smillert 		    "The number of sectors per cylinder (Usually sectors/track "
10414b9a3bdaSmillert 		    "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl,
10424b9a3bdaSmillert 		    0, 0);
10431e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
104496a888c6Smillert 			fputs("Command aborted\n", stderr);
104596a888c6Smillert 			*lp = oldlabel;		/* undo damage */
104696a888c6Smillert 			return;
10471e0ad43cSotto 		} else if (ui == ULLONG_MAX)
1048148b6188Smillert 			fputs("Invalid entry\n", stderr);
1049148b6188Smillert 		else
1050148b6188Smillert 			break;
1051148b6188Smillert 	}
1052148b6188Smillert 	lp->d_secpercyl = ui;
10536fe57b42Smillert 
10546fe57b42Smillert 	/* number of cylinders */
10556fe57b42Smillert 	for (;;) {
10566fe57b42Smillert 		ui = getuint(lp, 0, "number of cylinders",
10576fe57b42Smillert 		    "The total number of cylinders on the disk.",
10584b9a3bdaSmillert 		    lp->d_ncylinders, lp->d_ncylinders, 0, 0);
10591e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
106096a888c6Smillert 			fputs("Command aborted\n", stderr);
106196a888c6Smillert 			*lp = oldlabel;		/* undo damage */
106296a888c6Smillert 			return;
10631e0ad43cSotto 		} else if (ui == ULLONG_MAX)
10646fe57b42Smillert 			fputs("Invalid entry\n", stderr);
10656fe57b42Smillert 		else
10666fe57b42Smillert 			break;
10676fe57b42Smillert 	}
10686fe57b42Smillert 	lp->d_ncylinders = ui;
10696fe57b42Smillert 
10706fe57b42Smillert 	/* total sectors */
10716fe57b42Smillert 	for (;;) {
107234af67a3Sotto 		u_int64_t nsec = MAX(DL_GETDSIZE(lp),
107334af67a3Sotto 		    (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
10746fe57b42Smillert 		ui = getuint(lp, 0, "total sectors",
10756fe57b42Smillert 		    "The total number of sectors on the disk.",
1076baaa8969Smillert 		    nsec, nsec, 0, 0);
10771e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
107896a888c6Smillert 			fputs("Command aborted\n", stderr);
107996a888c6Smillert 			*lp = oldlabel;		/* undo damage */
108096a888c6Smillert 			return;
10811e0ad43cSotto 		} else if (ui == ULLONG_MAX)
10826fe57b42Smillert 			fputs("Invalid entry\n", stderr);
10831e0ad43cSotto 		else if (ui > DL_GETDSIZE(lp) &&
10841e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
1085f98aebd4Smillert 			puts("You may want to increase the size of the 'c' "
1086f98aebd4Smillert 			    "partition.");
10876fe57b42Smillert 			break;
10881e0ad43cSotto 		} else if (ui < DL_GETDSIZE(lp) &&
10891e0ad43cSotto 		    ending_sector == DL_GETDSIZE(lp)) {
10906fe57b42Smillert 			/* shrink free count */
10919fdcb4d6Skrw 			freesectors = editor_countfree(lp);
10929fdcb4d6Skrw 			if (DL_GETDSIZE(lp) - ui > freesectors)
10936fe57b42Smillert 				fprintf(stderr,
10941e0ad43cSotto 				    "Not enough free space to shrink by %llu "
10951e0ad43cSotto 				    "sectors (only %llu sectors left)\n",
10969fdcb4d6Skrw 				    DL_GETDSIZE(lp) - ui, freesectors);
1097c4f83f03Skrw 			else
10986fe57b42Smillert 				break;
10996fe57b42Smillert 		} else
11006fe57b42Smillert 			break;
11016fe57b42Smillert 	}
110241ed49b7Smillert 	/* Adjust ending_sector if necessary. */
110396a888c6Smillert 	if (ending_sector > ui)
110496a888c6Smillert 		ending_sector = ui;
11051e0ad43cSotto 	DL_SETDSIZE(lp, ui);
11066fe57b42Smillert 
11076fe57b42Smillert 	/* rpm */
11086fe57b42Smillert 	for (;;) {
11096fe57b42Smillert 		ui = getuint(lp, 0, "rpm",
1110a7e61405Smillert 		  "The rotational speed of the disk in revolutions per minute.",
11114b9a3bdaSmillert 		  lp->d_rpm, lp->d_rpm, 0, 0);
11121e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
111396a888c6Smillert 			fputs("Command aborted\n", stderr);
111496a888c6Smillert 			*lp = oldlabel;		/* undo damage */
111596a888c6Smillert 			return;
11161e0ad43cSotto 		} else if (ui == ULLONG_MAX)
11176fe57b42Smillert 			fputs("Invalid entry\n", stderr);
11186fe57b42Smillert 		else
11196fe57b42Smillert 			break;
11206fe57b42Smillert 	}
11216fe57b42Smillert 	lp->d_rpm = ui;
1122440b1d70Smillert 
1123440b1d70Smillert 	/* interleave */
1124440b1d70Smillert 	for (;;) {
1125440b1d70Smillert 		ui = getuint(lp, 0, "interleave",
1126440b1d70Smillert 		  "The physical sector interleave, set when formatting.  Almost always 1.",
11274b9a3bdaSmillert 		  lp->d_interleave, lp->d_interleave, 0, 0);
11281e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
1129440b1d70Smillert 			fputs("Command aborted\n", stderr);
1130440b1d70Smillert 			*lp = oldlabel;		/* undo damage */
1131440b1d70Smillert 			return;
11321e0ad43cSotto 		} else if (ui == ULLONG_MAX || ui == 0)
1133440b1d70Smillert 			fputs("Invalid entry\n", stderr);
1134440b1d70Smillert 		else
1135440b1d70Smillert 			break;
1136440b1d70Smillert 	}
1137440b1d70Smillert 	lp->d_interleave = ui;
11386fe57b42Smillert }
1139a7e61405Smillert 
1140a7e61405Smillert struct partition **
11418809fabbSderaadt sort_partitions(struct disklabel *lp, u_int16_t *npart)
1142a7e61405Smillert {
1143*d18c2a43Skrw 	static struct partition *spp[MAXPARTITIONS+2];
1144a7e61405Smillert 	u_int16_t npartitions;
1145a7e61405Smillert 	int i;
1146a7e61405Smillert 
1147*d18c2a43Skrw 	memset(spp, 0, sizeof(spp));
1148*d18c2a43Skrw 
1149a7e61405Smillert 	/* How many "real" partitions do we have? */
1150a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1151a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1152a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
11531e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1154a7e61405Smillert 			npartitions++;
1155a7e61405Smillert 	}
115696a888c6Smillert 	if (npartitions == 0) {
115796a888c6Smillert 		*npart = 0;
115896a888c6Smillert 		return(NULL);
115996a888c6Smillert 	}
1160a7e61405Smillert 
1161a7e61405Smillert 	for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) {
1162a7e61405Smillert 		if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
1163a7e61405Smillert 		    lp->d_partitions[i].p_fstype != FS_BOOT &&
11641e0ad43cSotto 		    DL_GETPSIZE(&lp->d_partitions[i]) != 0)
1165a7e61405Smillert 			spp[npartitions++] = &lp->d_partitions[i];
1166a7e61405Smillert 	}
1167a7e61405Smillert 
1168a7e61405Smillert 	/*
1169a7e61405Smillert 	 * Sort the partitions based on starting offset.
1170a7e61405Smillert 	 * This is safe because we guarantee no overlap.
1171a7e61405Smillert 	 */
1172a7e61405Smillert 	if (npartitions > 1)
1173a7e61405Smillert 		if (heapsort((void *)spp, npartitions, sizeof(spp[0]),
1174a7e61405Smillert 		    partition_cmp))
1175a7e61405Smillert 			err(4, "failed to sort partition table");
1176a7e61405Smillert 
1177a7e61405Smillert 	*npart = npartitions;
1178a7e61405Smillert 	return(spp);
1179a7e61405Smillert }
11800f820bbbSmillert 
11810f820bbbSmillert /*
11820f820bbbSmillert  * Get a valid disk type if necessary.
11830f820bbbSmillert  */
11840f820bbbSmillert void
11858809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev)
11860f820bbbSmillert {
11870f820bbbSmillert 	int i;
1188803ff7d5Smillert 	char *s, *def = "SCSI";
1189803ff7d5Smillert 	struct dtypes {
1190803ff7d5Smillert 		char *dev;
1191803ff7d5Smillert 		char *type;
1192803ff7d5Smillert 	} dtypes[] = {
1193c33fcabaSmillert 		{ "sd",   "SCSI" },
1194c33fcabaSmillert 		{ "rz",   "SCSI" },
1195c33fcabaSmillert 		{ "wd",   "IDE" },
1196c33fcabaSmillert 		{ "fd",   "FLOPPY" },
1197c33fcabaSmillert 		{ "xd",   "SMD" },
1198c33fcabaSmillert 		{ "xy",   "SMD" },
1199c33fcabaSmillert 		{ "hd",   "HP-IB" },
1200c33fcabaSmillert 		{ "ccd",  "CCD" },
1201c33fcabaSmillert 		{ "vnd",  "VND" },
1202c33fcabaSmillert 		{ "svnd", "VND" },
1203c33fcabaSmillert 		{ NULL,   NULL }
1204803ff7d5Smillert 	};
1205803ff7d5Smillert 
1206803ff7d5Smillert 	if ((s = basename(dev)) != NULL) {
1207803ff7d5Smillert 		if (*s == 'r')
1208803ff7d5Smillert 			s++;
1209803ff7d5Smillert 		i = strcspn(s, "0123456789");
1210803ff7d5Smillert 		s[i] = '\0';
1211803ff7d5Smillert 		dev = s;
1212803ff7d5Smillert 		for (i = 0; dtypes[i].dev != NULL; i++) {
1213803ff7d5Smillert 			if (strcmp(dev, dtypes[i].dev) == 0) {
1214803ff7d5Smillert 				def = dtypes[i].type;
1215803ff7d5Smillert 				break;
1216803ff7d5Smillert 			}
1217803ff7d5Smillert 		}
1218803ff7d5Smillert 	}
12190f820bbbSmillert 
12200f820bbbSmillert 	if (lp->d_type > DKMAXTYPES || lp->d_type == 0) {
12210f820bbbSmillert 		puts(banner);
12220f820bbbSmillert 		puts("Possible values are:");
1223eb5dd924Sderaadt 		printf("\"IDE\", ");
12240f820bbbSmillert 		for (i = 1; i < DKMAXTYPES; i++) {
12250f820bbbSmillert 			printf("\"%s\"", dktypenames[i]);
12260f820bbbSmillert 			if (i < DKMAXTYPES - 1)
12270f820bbbSmillert 				fputs(", ", stdout);
12280f820bbbSmillert 		}
12290f820bbbSmillert 		putchar('\n');
12300f820bbbSmillert 
12310f820bbbSmillert 		for (;;) {
1232c33fcabaSmillert 			s = getstring("Disk type",
1233803ff7d5Smillert 			    "What kind of disk is this?  Usually SCSI, IDE, "
1234803ff7d5Smillert 			    "ESDI, CCD, ST506, or floppy.", def);
123596a888c6Smillert 			if (s == NULL)
123696a888c6Smillert 				continue;
12375b412421Smillert 			if (strcasecmp(s, "IDE") == 0) {
12385b412421Smillert 				lp->d_type = DTYPE_ESDI;
12395b412421Smillert 				return;
12405b412421Smillert 			}
12410f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++)
12420f820bbbSmillert 				if (strcasecmp(s, dktypenames[i]) == 0) {
12430f820bbbSmillert 					lp->d_type = i;
12440f820bbbSmillert 					return;
12450f820bbbSmillert 				}
12460f820bbbSmillert 			printf("\"%s\" is not a valid disk type.\n", s);
12470f820bbbSmillert 			fputs("Valid types are: ", stdout);
12480f820bbbSmillert 			for (i = 1; i < DKMAXTYPES; i++) {
12490f820bbbSmillert 				printf("\"%s\"", dktypenames[i]);
12500f820bbbSmillert 				if (i < DKMAXTYPES - 1)
12510f820bbbSmillert 					fputs(", ", stdout);
12520f820bbbSmillert 			}
12530f820bbbSmillert 			putchar('\n');
12540f820bbbSmillert 		}
12550f820bbbSmillert 	}
12560f820bbbSmillert }
125796a888c6Smillert 
125896a888c6Smillert /*
125996a888c6Smillert  * Get beginning and ending sectors of the OpenBSD portion of the disk
126096a888c6Smillert  * from the user.
12614793b14cSmillert  * XXX - should mention MBR values if DOSLABEL
126296a888c6Smillert  */
126396a888c6Smillert void
12649fdcb4d6Skrw set_bounds(struct disklabel *lp)
126596a888c6Smillert {
12661e0ad43cSotto 	u_int64_t ui, start_temp;
126796a888c6Smillert 
126896a888c6Smillert 	/* Starting sector */
126996a888c6Smillert 	do {
127096a888c6Smillert 		ui = getuint(lp, 0, "Starting sector",
127196a888c6Smillert 		  "The start of the OpenBSD portion of the disk.",
12721e0ad43cSotto 		  starting_sector, DL_GETDSIZE(lp), 0, 0);
12731e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
127496a888c6Smillert 			fputs("Command aborted\n", stderr);
127596a888c6Smillert 			return;
127696a888c6Smillert 		}
12771e0ad43cSotto 	} while (ui >= DL_GETDSIZE(lp));
127896a888c6Smillert 	start_temp = ui;
127996a888c6Smillert 
12804793b14cSmillert 	/* Size */
128196a888c6Smillert 	do {
1282f98aebd4Smillert 		ui = getuint(lp, 0, "Size ('*' for entire disk)",
1283f98aebd4Smillert 		  "The size of the OpenBSD portion of the disk ('*' for the "
1284f98aebd4Smillert 		  "entire disk).", ending_sector - starting_sector,
12851e0ad43cSotto 		  DL_GETDSIZE(lp) - start_temp, 0, 0);
12861e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
128796a888c6Smillert 			fputs("Command aborted\n", stderr);
128896a888c6Smillert 			return;
128996a888c6Smillert 		}
12901e0ad43cSotto 	} while (ui > DL_GETDSIZE(lp) - start_temp);
12914793b14cSmillert 	ending_sector = start_temp + ui;
129296a888c6Smillert 	starting_sector = start_temp;
129396a888c6Smillert }
129496a888c6Smillert 
129596a888c6Smillert /*
129696a888c6Smillert  * Return a list of the "chunks" of free space available
129796a888c6Smillert  */
129896a888c6Smillert struct diskchunk *
12998809fabbSderaadt free_chunks(struct disklabel *lp)
130096a888c6Smillert {
130196a888c6Smillert 	u_int16_t npartitions;
130296a888c6Smillert 	struct partition **spp;
130396a888c6Smillert 	static struct diskchunk chunks[MAXPARTITIONS + 2];
130496a888c6Smillert 	int i, numchunks;
130596a888c6Smillert 
130696a888c6Smillert 	/* Sort the partitions based on offset */
130796a888c6Smillert 	spp = sort_partitions(lp, &npartitions);
130896a888c6Smillert 
130996a888c6Smillert 	/* If there are no partitions, it's all free. */
131096a888c6Smillert 	if (spp == NULL) {
13112d8451b0Smillert 		chunks[0].start = starting_sector;
131296a888c6Smillert 		chunks[0].stop = ending_sector;
131396a888c6Smillert 		chunks[1].start = chunks[1].stop = 0;
131496a888c6Smillert 		return(chunks);
131596a888c6Smillert 	}
131696a888c6Smillert 
131796a888c6Smillert 	/* Find chunks of free space */
131896a888c6Smillert 	numchunks = 0;
1319749c5bcaSkrw 	if (spp && DL_GETPOFFSET(spp[0]) > starting_sector) {
13202d8451b0Smillert 		chunks[0].start = starting_sector;
13211e0ad43cSotto 		chunks[0].stop = DL_GETPOFFSET(spp[0]);
132296a888c6Smillert 		numchunks++;
132396a888c6Smillert 	}
132496a888c6Smillert 	for (i = 0; i < npartitions; i++) {
132596a888c6Smillert 		if (i + 1 < npartitions) {
13261e0ad43cSotto 			u_int o1 = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
13271e0ad43cSotto 			u_int o2 = DL_GETPOFFSET(spp[i+1]);
13281e0ad43cSotto 			if (o1 < o2) {
13291e0ad43cSotto 				chunks[numchunks].start = o1;
13301e0ad43cSotto 				chunks[numchunks].stop = o2;
133196a888c6Smillert 				numchunks++;
133296a888c6Smillert 			}
133396a888c6Smillert 		} else {
13341e0ad43cSotto 			u_int o1 = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]);
133596a888c6Smillert 			/* Last partition */
13361e0ad43cSotto 			if (o1 < ending_sector) {
133796a888c6Smillert 
13381e0ad43cSotto 				chunks[numchunks].start = o1;
133965ce672dScsapuntz 				chunks[numchunks].stop = ending_sector;
134096a888c6Smillert 				numchunks++;
134196a888c6Smillert 			}
134296a888c6Smillert 		}
134396a888c6Smillert 	}
134496a888c6Smillert 
134596a888c6Smillert 	/* Terminate and return */
134696a888c6Smillert 	chunks[numchunks].start = chunks[numchunks].stop = 0;
134796a888c6Smillert 	return(chunks);
134896a888c6Smillert }
13494793b14cSmillert 
13504793b14cSmillert /*
13514793b14cSmillert  * What is the OpenBSD portion of the disk?  Uses the MBR if applicable.
13524793b14cSmillert  */
13534793b14cSmillert void
135487023ed9Skrw find_bounds(struct disklabel *lp)
13554793b14cSmillert {
1356a4df0321Sderaadt #ifdef DOSLABEL
1357d09f3941Smillert 	struct partition *pp = &lp->d_partitions[RAW_PART];
1358a4df0321Sderaadt #endif
13594793b14cSmillert 	/* Defaults */
13604793b14cSmillert 	/* XXX - reserve a cylinder for hp300? */
13614793b14cSmillert 	starting_sector = 0;
13621e0ad43cSotto 	ending_sector = DL_GETDSIZE(lp);
13634793b14cSmillert 
13644793b14cSmillert #ifdef DOSLABEL
1365528915f5Smillert 	/*
136630eb6e87Skrw 	 * If we have an MBR, use values from the OpenBSD partition.
1367528915f5Smillert 	 */
1368d09f3941Smillert 	if (dosdp) {
136930eb6e87Skrw 	    if (dosdp->dp_typ == DOSPTYP_OPENBSD) {
1370528915f5Smillert 			u_int32_t i, new_end;
1371528915f5Smillert 
1372d09f3941Smillert 			/* Set start and end based on fdisk partition bounds */
137326cb38f1Skrw 			starting_sector = letoh32(dosdp->dp_start);
137426cb38f1Skrw 			ending_sector = starting_sector + letoh32(dosdp->dp_size);
1375528915f5Smillert 
1376528915f5Smillert 			/*
1377d09f3941Smillert 			 * If there are any BSD or SWAP partitions beyond
1378d09f3941Smillert 			 * ending_sector we extend ending_sector to include
1379d09f3941Smillert 			 * them.  This is done because the BIOS geometry is
1380d09f3941Smillert 			 * generally different from the disk geometry.
1381528915f5Smillert 			 */
1382528915f5Smillert 			for (i = new_end = 0; i < lp->d_npartitions; i++) {
1383528915f5Smillert 				pp = &lp->d_partitions[i];
1384528915f5Smillert 				if ((pp->p_fstype == FS_BSDFFS ||
1385528915f5Smillert 				    pp->p_fstype == FS_SWAP) &&
138634af67a3Sotto 				    DL_GETPSIZE(pp) + DL_GETPOFFSET(pp) >
138734af67a3Sotto 					new_end)
138834af67a3Sotto 					new_end = DL_GETPSIZE(pp) +
138934af67a3Sotto 					    DL_GETPOFFSET(pp);
1390528915f5Smillert 			}
1391528915f5Smillert 			if (new_end > ending_sector)
1392528915f5Smillert 				ending_sector = new_end;
1393d09f3941Smillert 		} else {
1394d09f3941Smillert 			/* Don't trounce the MBR */
13959785f718Smillert 			starting_sector = 63;
1396d09f3941Smillert 		}
1397d09f3941Smillert 
13986893bfe5Sderaadt 		printf("Treating sectors %llu-%llu as the OpenBSD portion of the "
13996893bfe5Sderaadt 		    "disk.\nYou can use the 'b' command to change this.\n\n",
14004793b14cSmillert 		    starting_sector, ending_sector);
14014793b14cSmillert 	}
1402d3f02056Smillert #elif (NUMBOOT == 1)
1403d3f02056Smillert 	/* Boot blocks take up the first cylinder */
1404d3f02056Smillert 	starting_sector = lp->d_secpercyl;
14056893bfe5Sderaadt 	printf("Reserving the first data cylinder for boot blocks.\n"
14066893bfe5Sderaadt 	    "You can use the 'b' command to change this.\n\n");
14074793b14cSmillert #endif
14084793b14cSmillert }
1409c0bdc608Smillert 
1410c0bdc608Smillert /*
1411c0bdc608Smillert  * Calculate free space.
1412c0bdc608Smillert  */
14139fdcb4d6Skrw u_int64_t
14149fdcb4d6Skrw editor_countfree(struct disklabel *lp)
1415c0bdc608Smillert {
1416d93cb2bbSkrw 	struct diskchunk *chunks;
14179fdcb4d6Skrw 	u_int64_t freesectors = 0;
1418c0bdc608Smillert 	int i;
1419c0bdc608Smillert 
1420d93cb2bbSkrw 	chunks = free_chunks(lp);
1421509930fbSotto 
1422d93cb2bbSkrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++)
14239fdcb4d6Skrw 		freesectors += chunks[i].stop - chunks[i].start;
14249fdcb4d6Skrw 
14259fdcb4d6Skrw 	return (freesectors);
1426c0bdc608Smillert }
1427617e6e4aSmillert 
1428617e6e4aSmillert void
14298809fabbSderaadt editor_help(char *arg)
1430617e6e4aSmillert {
1431617e6e4aSmillert 
1432617e6e4aSmillert 	/* XXX - put these strings in a table instead? */
1433617e6e4aSmillert 	switch (*arg) {
1434617e6e4aSmillert 	case 'p':
1435617e6e4aSmillert 		puts(
1436617e6e4aSmillert "The 'p' command prints the current disk label.  By default, it prints the\n"
1437617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes).  The 'p' command\n"
1438617e6e4aSmillert "takes an optional units argument.  Possible values are 'b' for bytes, 'c'\n"
1439617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n");
1440617e6e4aSmillert 		break;
1441617e6e4aSmillert 	case 'M':
1442617e6e4aSmillert 		puts(
14439afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n"
1444508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n"
1445508086e9Smillert "not set.  It is especially useful during install when the normal system\n"
1446508086e9Smillert "manual is not available.\n");
1447617e6e4aSmillert 		break;
1448617e6e4aSmillert 	case 'e':
1449617e6e4aSmillert 		puts(
1450617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters.  These include\n"
1451617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n"
1452617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n"
1453617e6e4aSmillert "type, and a descriptive label string.  You should not change these unless\n"
1454617e6e4aSmillert "you know what you are doing\n");
1455617e6e4aSmillert 		break;
1456617e6e4aSmillert 	case 'a':
1457617e6e4aSmillert 		puts(
1458617e6e4aSmillert "The 'a' command adds new partitions to the disk.  It takes as an optional\n"
1459617e6e4aSmillert "argument the partition letter to add.  If you do not specify a partition\n"
1460617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n"
1461617e6e4aSmillert "default answer\n");
1462617e6e4aSmillert 		break;
1463617e6e4aSmillert 	case 'b':
1464617e6e4aSmillert 		puts(
1465617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n"
1466617e6e4aSmillert "the disk.  This is only useful on disks with an fdisk partition.  By default,\n"
1467617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n"
1468617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition.  You should only change\n"
1469617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n"
1470617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be.  You\n"
1471617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n"
1472617e6e4aSmillert "(minus the starting sector).  Use this option with care; if you extend the\n"
1473617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n"
1474617e6e4aSmillert "corrupt the other operating system's data.\n");
1475617e6e4aSmillert 		break;
1476617e6e4aSmillert 	case 'c':
1477617e6e4aSmillert 		puts(
1478617e6e4aSmillert "The 'c' command is used to change the size of an existing partition.  It\n"
1479617e6e4aSmillert "takes as an optional argument the partition letter to change.  If you do not\n"
1480617e6e4aSmillert "specify a partition letter, you will be prompted for one.  You may add a '+'\n"
1481617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n"
1482617e6e4aSmillert "instead of entering an absolute value.  You may also use a suffix to indicate\n"
1483617e6e4aSmillert "the units the values is in terms of.  Possible suffixes are 'b' for bytes,\n"
1484617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n"
1485617e6e4aSmillert "no suffix for sectors (usually 512 bytes).  You may also enter '*' to change\n"
1486617e6e4aSmillert "the size to be the total number of free sectors remaining.\n");
1487617e6e4aSmillert 		break;
14889afbe9eeSmillert 	case 'D':
14899afbe9eeSmillert 		puts(
14909afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n"
14919afbe9eeSmillert "by the disk itself.  This similates the case where there is no disk label.\n");
14929afbe9eeSmillert 		break;
1493617e6e4aSmillert 	case 'd':
1494617e6e4aSmillert 		puts(
1495617e6e4aSmillert "The 'd' command is used to delete an existing partition.  It takes as an\n"
1496617e6e4aSmillert "optional argument the partition letter to change.  If you do not specify a\n"
1497617e6e4aSmillert "partition letter, you will be prompted for one.  You may not delete the ``c''\n"
1498617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n"
1499617e6e4aSmillert "it does not take up any space).\n");
1500617e6e4aSmillert 		break;
1501c33fcabaSmillert 	case 'g':
1502c33fcabaSmillert 		puts(
150387023ed9Skrw "The 'g' command is used select which disk geometry to use, the disk or a\n"
150487023ed9Skrw "user geometry.  It takes as an optional argument ``d'' or ``u''.  If \n"
1505c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n");
1506c33fcabaSmillert 		break;
1507617e6e4aSmillert 	case 'm':
1508617e6e4aSmillert 		puts(
150987023ed9Skrw "The 'm' command is used to modify an existing partition.  It takes as an\n"
151087023ed9Skrw "optional argument the partition letter to change.  If you do not specify a\n"
1511617e6e4aSmillert "partition letter, you will be prompted for one.  This option allows the user\n"
1512617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n"
1513617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n"
1514617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n");
1515617e6e4aSmillert 		break;
1516bd6726faSmillert 	case 'n':
1517bd6726faSmillert 		puts(
1518fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n"
1519bd6726faSmillert "It takes as an optional argument the partition letter to name.  If you do\n"
1520bd6726faSmillert "not specify a partition letter, you will be prompted for one.  This option\n"
1521bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n");
1522bd6726faSmillert 		break;
1523617e6e4aSmillert 	case 'r':
1524617e6e4aSmillert 		puts(
152525f9c360Skrw "The 'r' command is used to recalculate and display details about\n"
152625f9c360Skrw "the available free space.\n");
1527617e6e4aSmillert 		break;
1528617e6e4aSmillert 	case 'u':
1529617e6e4aSmillert 		puts(
1530617e6e4aSmillert "The 'u' command will undo (or redo) the last change.  Entering 'u' once will\n"
1531617e6e4aSmillert "undo your last change.  Entering it again will restore the change.\n");
1532617e6e4aSmillert 		break;
1533617e6e4aSmillert 	case 's':
1534617e6e4aSmillert 		puts(
1535617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n"
1536617e6e4aSmillert "(suitable for loading via disklabel's [-R] option).  It takes as an optional\n"
1537617e6e4aSmillert "argument the filename to save the label to.  If you do not specify a filename,\n"
1538617e6e4aSmillert "you will be prompted for one.\n");
1539617e6e4aSmillert 		break;
1540617e6e4aSmillert 	case 'w':
1541617e6e4aSmillert 		puts(
1542617e6e4aSmillert "The 'w' command will write the current label to disk.  This option will\n"
1543617e6e4aSmillert "commit any changes to the on-disk label.\n");
1544617e6e4aSmillert 		break;
1545617e6e4aSmillert 	case 'q':
1546617e6e4aSmillert 		puts(
1547617e6e4aSmillert "The 'q' command quits the label editor.  If any changes have been made you\n"
1548617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n");
1549617e6e4aSmillert 		break;
15509afbe9eeSmillert 	case 'X':
15519afbe9eeSmillert 		puts(
15529afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'.  By default,\n"
15539afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n"
15549afbe9eeSmillert "size on ffs partitions).\n");
15559afbe9eeSmillert 		break;
1556617e6e4aSmillert 	case 'x':
1557617e6e4aSmillert 		puts(
1558617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n"
1559617e6e4aSmillert "on-disk label.\n");
1560617e6e4aSmillert 		break;
15619afbe9eeSmillert 	case 'z':
15629afbe9eeSmillert 		puts(
15639afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n"
15649afbe9eeSmillert "partition.  The drive parameters are not changed.\n");
15659afbe9eeSmillert 		break;
1566617e6e4aSmillert 	default:
1567617e6e4aSmillert 		puts("Available commands:");
156852317843Sjmc 		puts("\t? [cmnd]  - this message or command specific help.");
1569617e6e4aSmillert 		puts("\ta [part]  - add new partition.");
1570617e6e4aSmillert 		puts("\tb         - set OpenBSD disk boundaries.");
1571617e6e4aSmillert 		puts("\tc [part]  - change partition size.");
15729afbe9eeSmillert 		puts("\tD         - set label to default.");
157352317843Sjmc 		puts("\td [part]  - delete partition.");
157452317843Sjmc 		puts("\te         - edit drive parameters.");
157587023ed9Skrw 		puts("\tg [d|u]   - use [d]isk or [u]ser geometry.");
157652317843Sjmc 		puts("\tM         - show entire OpenBSD man page for disklabel.");
1577617e6e4aSmillert 		puts("\tm [part]  - modify existing partition.");
1578bd6726faSmillert 		puts("\tn [part]  - set the mount point for a partition.");
157952317843Sjmc 		puts("\tp [unit]  - print label.");
1580617e6e4aSmillert 		puts("\tq         - quit and save changes.");
158125f9c360Skrw 		puts("\tr         - recalculate & display free space details.");
158252317843Sjmc 		puts("\ts [path]  - save label to file.");
158352317843Sjmc 		puts("\tu         - undo last change.");
158452317843Sjmc 		puts("\tw         - write label to disk.");
15852d8451b0Smillert 		puts("\tX         - toggle expert mode.");
158652317843Sjmc 		puts("\tx         - exit without saving changes.");
15879afbe9eeSmillert 		puts("\tz         - zero out partition table.");
1588617e6e4aSmillert 		puts(
1589617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t"
1590617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t"
1591617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t"
159214cc915fSmillert "'%' for percent of total disk size, '&' for percent of free space.\n\t"
1593617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n"
1594617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help.");
1595617e6e4aSmillert 		break;
1596617e6e4aSmillert 	}
1597617e6e4aSmillert }
1598bd6726faSmillert 
1599bd6726faSmillert char **
16008809fabbSderaadt mpcopy(char **to, char **from)
1601bd6726faSmillert {
1602bd6726faSmillert 	int i;
16030612d09dSderaadt 	char *top;
1604bd6726faSmillert 
1605bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1606bd6726faSmillert 		if (from[i] != NULL) {
1607dcab0d16Sderaadt 			int len = strlen(from[i]) + 1;
1608dcab0d16Sderaadt 
16090612d09dSderaadt 			top = realloc(to[i], len);
16100612d09dSderaadt 			if (top == NULL)
1611bd6726faSmillert 				errx(4, "out of memory");
16120612d09dSderaadt 			to[i] = top;
1613dcab0d16Sderaadt 			(void)strlcpy(to[i], from[i], len);
1614bd6726faSmillert 		} else if (to[i] != NULL) {
1615bd6726faSmillert 			free(to[i]);
1616bd6726faSmillert 			to[i] = NULL;
1617bd6726faSmillert 		}
1618bd6726faSmillert 	}
1619bd6726faSmillert 	return(to);
1620bd6726faSmillert }
1621bd6726faSmillert 
1622bd6726faSmillert int
16238809fabbSderaadt mpequal(char **mp1, char **mp2)
1624bd6726faSmillert {
1625bd6726faSmillert 	int i;
1626bd6726faSmillert 
1627bd6726faSmillert 	for (i = 0; i < MAXPARTITIONS; i++) {
1628bd6726faSmillert 		if (mp1[i] == NULL && mp2[i] == NULL)
1629bd6726faSmillert 			continue;
1630bd6726faSmillert 
1631bd6726faSmillert 		if ((mp1[i] != NULL && mp2[i] == NULL) ||
1632bd6726faSmillert 		    (mp1[i] == NULL && mp2[i] != NULL) ||
1633bd6726faSmillert 		    (strcmp(mp1[i], mp2[i]) != 0))
1634bd6726faSmillert 			return(0);
1635bd6726faSmillert 	}
1636bd6726faSmillert 	return(1);
1637bd6726faSmillert }
1638bd6726faSmillert 
1639bd6726faSmillert int
16408809fabbSderaadt mpsave(struct disklabel *lp, char **mp, char *cdev, char *fstabfile)
1641bd6726faSmillert {
16425fea0b85Smillert 	int i, j, mpset;
1643bd6726faSmillert 	char bdev[MAXPATHLEN], *p;
16443f843443Smillert 	struct mountinfo mi[MAXPARTITIONS];
1645bd6726faSmillert 	FILE *fp;
1646bd6726faSmillert 
16473f843443Smillert 	memset(&mi, 0, sizeof(mi));
16483f843443Smillert 
1649bd6726faSmillert 	for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) {
1650bd6726faSmillert 		if (mp[i] != NULL) {
16513f843443Smillert 			mi[i].mountpoint = mp[i];
16523f843443Smillert 			mi[i].partno = i;
1653bd6726faSmillert 			mpset = 1;
1654bd6726faSmillert 		}
1655bd6726faSmillert 	}
16563f843443Smillert 	/* Exit if there is nothing to do... */
1657bd6726faSmillert 	if (!mpset)
16583f843443Smillert 		return(0);
1659bd6726faSmillert 
1660bd6726faSmillert 	/* Convert cdev to bdev */
1661bd6726faSmillert 	if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 &&
1662bd6726faSmillert 	    cdev[sizeof(_PATH_DEV) - 1] == 'r') {
1663bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV,
1664bd6726faSmillert 		    &cdev[sizeof(_PATH_DEV)]);
1665bd6726faSmillert 	} else {
1666bd6726faSmillert 		if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r')
1667bd6726faSmillert 			return(1);
1668bd6726faSmillert 		*p = '\0';
1669bd6726faSmillert 		snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1);
1670bd6726faSmillert 		*p = 'r';
1671bd6726faSmillert 	}
1672bd6726faSmillert 	bdev[strlen(bdev) - 1] = '\0';
1673bd6726faSmillert 
16743f843443Smillert 	/* Sort mountpoints so we don't try to mount /usr/local before /usr */
16753f843443Smillert 	qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp);
16763f843443Smillert 
1677bd6726faSmillert 	if ((fp = fopen(fstabfile, "w")) == NULL)
1678bd6726faSmillert 		return(1);
1679bd6726faSmillert 
16803f843443Smillert 	for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) {
16815fea0b85Smillert 		j =  mi[i].partno;
16825fea0b85Smillert 		fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j,
16833f843443Smillert 		    mi[i].mountpoint,
16845fea0b85Smillert 		    fstypesnames[lp->d_partitions[j].p_fstype],
16855fea0b85Smillert 		    j == 0 ? 1 : 2);
1686bd6726faSmillert 	}
1687bd6726faSmillert 	fclose(fp);
1688bd6726faSmillert 	return(0);
1689bd6726faSmillert }
169024a2c1a4Smillert 
169124a2c1a4Smillert int
1692604d3bdeSkrw get_offset(struct disklabel *lp, int partno)
169324a2c1a4Smillert {
1694604d3bdeSkrw 	struct diskchunk *chunks;
169524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
169615c15d8aSkrw 	u_int64_t ui, maxsize;
1697604d3bdeSkrw 	int i, fstype;
169824a2c1a4Smillert 
169924a2c1a4Smillert 	ui = getuint(lp, partno, "offset",
17001e0ad43cSotto 	   "Starting sector for this partition.",
17011e0ad43cSotto 	   DL_GETPOFFSET(pp),
17021e0ad43cSotto 	   DL_GETPOFFSET(pp), 0, DO_CONVERSIONS |
170324a2c1a4Smillert 	   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));
1704e9ff19beSkrw 
1705e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
170624a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1707e9ff19beSkrw 	else if (ui == ULLONG_MAX)
170824a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
170940e98e9fSkrw 	else if (ui < starting_sector || ui >= ending_sector)
1710e9ff19beSkrw 		fprintf(stderr, "The offset must be >= %llu and < %llu, "
1711e9ff19beSkrw 		    "the limits of the OpenBSD portion\n"
1712e9ff19beSkrw 		    "of the disk. The 'b' command can change these limits.\n",
171340e98e9fSkrw 		    starting_sector, ending_sector);
1714fc1a4cc6Sderaadt #ifdef SUN_AAT0
171549bf537cSderaadt 	else if (partno == 0 && ui != 0)
171649bf537cSderaadt 		fprintf(stderr, "This architecture requires that "
171740f544cdSderaadt 		    "partition 'a' start at sector 0.\n");
171849bf537cSderaadt #endif
171915c15d8aSkrw 	else {
1720604d3bdeSkrw 		fstype = pp->p_fstype;
1721604d3bdeSkrw 		pp->p_fstype = FS_UNUSED;
1722604d3bdeSkrw 		chunks = free_chunks(lp);
1723604d3bdeSkrw 		pp->p_fstype = fstype;
1724e9ff19beSkrw 		for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
1725e9ff19beSkrw 			if (ui < chunks[i].start || ui >= chunks[i].stop)
172615c15d8aSkrw 				continue;
17271e0ad43cSotto 			DL_SETPOFFSET(pp, ui);
172815c15d8aSkrw 			maxsize = chunks[i].stop - DL_GETPOFFSET(pp);
172915c15d8aSkrw 			if (DL_GETPSIZE(pp) > maxsize)
173015c15d8aSkrw 				DL_SETPSIZE(pp, maxsize);
173124a2c1a4Smillert 			return (0);
173224a2c1a4Smillert 		}
173315c15d8aSkrw 		fputs("The offset must be in a free area.\n", stderr);
173415c15d8aSkrw 	}
1735e9ff19beSkrw 
1736e9ff19beSkrw 	/* Partition offset was not set. */
1737e9ff19beSkrw 	return (1);
173815c15d8aSkrw }
173924a2c1a4Smillert 
174024a2c1a4Smillert int
17419fdcb4d6Skrw get_size(struct disklabel *lp, int partno)
174224a2c1a4Smillert {
174324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
174414192793Skrw 	u_int64_t maxsize, ui;
174514192793Skrw 
174614192793Skrw 	maxsize = max_partition_size(lp, partno);
174724a2c1a4Smillert 
17487da73705Skrw 	ui = getuint(lp, partno, "size", "Size of the partition. "
17497da73705Skrw 	    "You may also say +/- amount for a relative change.",
175014192793Skrw 	    DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp),
1751525051f1Sotto 	    DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS ||
1752525051f1Sotto 	    pp->p_fstype == FS_SWAP) ?  DO_ROUNDING : 0));
1753e9ff19beSkrw 
1754e9ff19beSkrw 	if (ui == ULLONG_MAX - 1)
175524a2c1a4Smillert 		fputs("Command aborted\n", stderr);
1756e9ff19beSkrw 	else if (ui == ULLONG_MAX)
175724a2c1a4Smillert 		fputs("Invalid entry\n", stderr);
175828e3704eSkrw 	else if (ui == 0)
175928e3704eSkrw 		fputs("The size must be > 0\n", stderr);
176040e98e9fSkrw 	else if (ui + DL_GETPOFFSET(pp) > ending_sector)
176140e98e9fSkrw 		fprintf(stderr, "The size can't be more than "
176240e98e9fSkrw 		    "%llu sectors, or the partition would\n"
176340e98e9fSkrw 		    "extend beyond the last sector (%llu) of the "
176440e98e9fSkrw 		    "OpenBSD portion of\nthe disk. "
176540e98e9fSkrw 		    "The 'b' command can change this limit.\n",
176640e98e9fSkrw 		    ending_sector - DL_GETPOFFSET(pp), ending_sector);
176714192793Skrw 	else if (ui > maxsize)
176814192793Skrw 		fprintf(stderr,"Sorry, there are only %llu sectors left\n",
176914192793Skrw 		    maxsize);
177059ccf790Skrw 	else {
177159ccf790Skrw 		DL_SETPSIZE(pp, ui);
177224a2c1a4Smillert 		return (0);
177324a2c1a4Smillert 	}
1774e9ff19beSkrw 
1775e9ff19beSkrw 	/* Partition size was not set. */
1776e9ff19beSkrw 	return (1);
1777e9ff19beSkrw }
177824a2c1a4Smillert 
177924a2c1a4Smillert int
17808809fabbSderaadt get_fsize(struct disklabel *lp, int partno)
178124a2c1a4Smillert {
17821e0ad43cSotto 	u_int64_t ui, fsize, frag;
178324a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
178424a2c1a4Smillert 
1785a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
1786a4c87e64Skrw 		return (0);
1787a4c87e64Skrw 
1788ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1789ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
1790ddfcbf38Sotto 	if (fsize == 0)
1791ddfcbf38Sotto 		frag = 8;
1792ddfcbf38Sotto 
179324a2c1a4Smillert 	for (;;) {
179424a2c1a4Smillert 		ui = getuint(lp, partno, "fragment size",
17953c92d7f2Stedu 		    "Size of fs block fragments.  Usually 2048 or 512.",
1796ddfcbf38Sotto 		    fsize, fsize, 0, 0);
17971e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
179824a2c1a4Smillert 			fputs("Command aborted\n", stderr);
179924a2c1a4Smillert 			return(1);
18001e0ad43cSotto 		} else if (ui == ULLONG_MAX)
180124a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
180224a2c1a4Smillert 		else
180324a2c1a4Smillert 			break;
180424a2c1a4Smillert 	}
180524a2c1a4Smillert 	if (ui == 0)
180624a2c1a4Smillert 		puts("Zero fragment size implies zero block size");
1807ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag);
180824a2c1a4Smillert 	return(0);
180924a2c1a4Smillert }
181024a2c1a4Smillert 
181124a2c1a4Smillert int
18128809fabbSderaadt get_bsize(struct disklabel *lp, int partno)
181324a2c1a4Smillert {
18141e0ad43cSotto 	u_int64_t ui, bsize, frag, fsize;
181524a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
181624a2c1a4Smillert 
1817a4c87e64Skrw 	if (!expert || pp->p_fstype != FS_BSDFFS)
1818a4c87e64Skrw 		return (0);
1819a4c87e64Skrw 
182024a2c1a4Smillert 	/* Avoid dividing by zero... */
1821ddfcbf38Sotto 	if (pp->p_fragblock == 0)
182224a2c1a4Smillert 		return(1);
1823ddfcbf38Sotto 
1824ddfcbf38Sotto 	bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock);
1825ddfcbf38Sotto 	fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
1826ddfcbf38Sotto 	frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
182724a2c1a4Smillert 
182824a2c1a4Smillert 	for (;;) {
182924a2c1a4Smillert 		ui = getuint(lp, partno, "block size",
18303c92d7f2Stedu 		    "Size of filesystem blocks.  Usually 16384 or 4096.",
1831ddfcbf38Sotto 		    fsize * frag, fsize * frag,
183224a2c1a4Smillert 		    0, 0);
183324a2c1a4Smillert 
183424a2c1a4Smillert 		/* sanity checks */
18351e0ad43cSotto 		if (ui == ULLONG_MAX - 1) {
183624a2c1a4Smillert 			fputs("Command aborted\n", stderr);
183724a2c1a4Smillert 			return(1);
18381e0ad43cSotto 		} else if (ui == ULLONG_MAX)
183924a2c1a4Smillert 			fputs("Invalid entry\n", stderr);
184024a2c1a4Smillert 		else if (ui < getpagesize())
184124a2c1a4Smillert 			fprintf(stderr,
184224a2c1a4Smillert 			    "Error: block size must be at least as big "
184324a2c1a4Smillert 			    "as page size (%d).\n", getpagesize());
1844ddfcbf38Sotto 		else if (ui % fsize != 0)
184524a2c1a4Smillert 			fputs("Error: block size must be a multiple of the "
184624a2c1a4Smillert 			    "fragment size.\n", stderr);
1847ddfcbf38Sotto 		else if (ui / fsize < 1)
184824a2c1a4Smillert 			fputs("Error: block size must be at least as big as "
184924a2c1a4Smillert 			    "fragment size.\n", stderr);
185024a2c1a4Smillert 		else
185124a2c1a4Smillert 			break;
185224a2c1a4Smillert 	}
1853ddfcbf38Sotto 	pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag);
185424a2c1a4Smillert 	return(0);
185524a2c1a4Smillert }
185624a2c1a4Smillert 
185724a2c1a4Smillert int
18588809fabbSderaadt get_fstype(struct disklabel *lp, int partno)
185924a2c1a4Smillert {
186024a2c1a4Smillert 	char *p;
18611e0ad43cSotto 	u_int64_t ui;
186224a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
186324a2c1a4Smillert 
186424a2c1a4Smillert 	if (pp->p_fstype < FSMAXTYPES) {
1865c33fcabaSmillert 		p = getstring("FS type",
186624a2c1a4Smillert 		    "Filesystem type (usually 4.2BSD or swap)",
186724a2c1a4Smillert 		    fstypenames[pp->p_fstype]);
186824a2c1a4Smillert 		if (p == NULL) {
186924a2c1a4Smillert 			fputs("Command aborted\n", stderr);
187024a2c1a4Smillert 			return(1);
187124a2c1a4Smillert 		}
187224a2c1a4Smillert 		for (ui = 0; ui < FSMAXTYPES; ui++) {
187324a2c1a4Smillert 			if (!strcasecmp(p, fstypenames[ui])) {
187424a2c1a4Smillert 				pp->p_fstype = ui;
187524a2c1a4Smillert 				break;
187624a2c1a4Smillert 			}
187724a2c1a4Smillert 		}
187824a2c1a4Smillert 		if (ui >= FSMAXTYPES) {
187924a2c1a4Smillert 			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);
188024a2c1a4Smillert 			pp->p_fstype = FS_OTHER;
188124a2c1a4Smillert 		}
188224a2c1a4Smillert 	} else {
188324a2c1a4Smillert 		for (;;) {
188424a2c1a4Smillert 			ui = getuint(lp, partno, "FS type (decimal)",
188524a2c1a4Smillert 			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",
188624a2c1a4Smillert 			    pp->p_fstype, pp->p_fstype, 0, 0);
18871e0ad43cSotto 			if (ui == ULLONG_MAX - 1) {
188824a2c1a4Smillert 				fputs("Command aborted\n", stderr);
188924a2c1a4Smillert 				return(1);
18901e0ad43cSotto 			} if (ui == ULLONG_MAX)
189124a2c1a4Smillert 				fputs("Invalid entry\n", stderr);
189224a2c1a4Smillert 			else
189324a2c1a4Smillert 				break;
189424a2c1a4Smillert 		}
189524a2c1a4Smillert 		pp->p_fstype = ui;
189624a2c1a4Smillert 	}
189724a2c1a4Smillert 	return(0);
189824a2c1a4Smillert }
189924a2c1a4Smillert 
190024a2c1a4Smillert int
19018809fabbSderaadt get_mp(struct disklabel *lp, char **mp, int partno)
190224a2c1a4Smillert {
190324a2c1a4Smillert 	char *p;
190424a2c1a4Smillert 	struct partition *pp = &lp->d_partitions[partno];
190524a2c1a4Smillert 
190624a2c1a4Smillert 	if (mp != NULL && pp->p_fstype != FS_UNUSED &&
190724a2c1a4Smillert 	    pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT &&
190824a2c1a4Smillert 	    pp->p_fstype != FS_OTHER) {
1909ddaff619Smillert 		for (;;) {
1910c33fcabaSmillert 			p = getstring("mount point",
191124a2c1a4Smillert 			    "Where to mount this filesystem (ie: / /var /usr)",
191224a2c1a4Smillert 			    mp[partno] ? mp[partno] : "none");
191324a2c1a4Smillert 			if (p == NULL) {
191424a2c1a4Smillert 				fputs("Command aborted\n", stderr);
191524a2c1a4Smillert 				return(1);
191624a2c1a4Smillert 			}
1917ddaff619Smillert 			if (strcasecmp(p, "none") == 0) {
191824a2c1a4Smillert 				if (mp[partno] != NULL) {
191924a2c1a4Smillert 					free(mp[partno]);
192024a2c1a4Smillert 					mp[partno] = NULL;
192124a2c1a4Smillert 				}
1922ddaff619Smillert 				break;
1923ddaff619Smillert 			}
1924ddaff619Smillert 			if (*p == '/') {
1925ddaff619Smillert 				/* XXX - might as well realloc */
1926ddaff619Smillert 				if (mp[partno] != NULL)
1927ddaff619Smillert 					free(mp[partno]);
192824a2c1a4Smillert 				if ((mp[partno] = strdup(p)) == NULL)
192924a2c1a4Smillert 					errx(4, "out of memory");
1930ddaff619Smillert 				break;
1931ddaff619Smillert 			}
1932ddaff619Smillert 			fputs("Mount points must start with '/'\n", stderr);
193324a2c1a4Smillert 		}
193424a2c1a4Smillert 	}
193524a2c1a4Smillert 	return(0);
193624a2c1a4Smillert }
19373f843443Smillert 
19383f843443Smillert int
19398809fabbSderaadt micmp(const void *a1, const void *a2)
19403f843443Smillert {
19413f843443Smillert 	struct mountinfo *mi1 = (struct mountinfo *)a1;
19423f843443Smillert 	struct mountinfo *mi2 = (struct mountinfo *)a2;
19433f843443Smillert 
19443f843443Smillert 	/* We want all the NULLs at the end... */
19453f843443Smillert 	if (mi1->mountpoint == NULL && mi2->mountpoint == NULL)
19463f843443Smillert 		return(0);
19473f843443Smillert 	else if (mi1->mountpoint == NULL)
19483f843443Smillert 		return(1);
19493f843443Smillert 	else if (mi2->mountpoint == NULL)
19503f843443Smillert 		return(-1);
19513f843443Smillert 	else
19523f843443Smillert 		return(strcmp(mi1->mountpoint, mi2->mountpoint));
19533f843443Smillert }
1954c33fcabaSmillert 
1955c33fcabaSmillert void
195687023ed9Skrw get_geometry(int f, struct disklabel **dgpp)
1957c33fcabaSmillert {
1958c33fcabaSmillert 	struct stat st;
1959c33fcabaSmillert 	struct disklabel *disk_geop;
196087023ed9Skrw 
1961c33fcabaSmillert 	if (fstat(f, &st) == -1)
1962c33fcabaSmillert 		err(4, "Can't stat device");
1963c33fcabaSmillert 
1964c33fcabaSmillert 	/* Get disk geometry */
1965c33fcabaSmillert 	if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL)
1966c33fcabaSmillert 		errx(4, "out of memory");
1967c33fcabaSmillert 	if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 &&
1968c33fcabaSmillert 	    ioctl(f, DIOCGDINFO, disk_geop) < 0)
1969c33fcabaSmillert 		err(4, "ioctl DIOCGDINFO");
1970c33fcabaSmillert 	*dgpp = disk_geop;
1971c33fcabaSmillert }
1972c33fcabaSmillert 
1973c33fcabaSmillert void
19748809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp,
197587023ed9Skrw     struct disklabel *ugp, char *p)
1976c33fcabaSmillert {
1977c33fcabaSmillert 	if (p == NULL) {
19789a36aa41Ssthen 		p = getstring("[d]isk or [u]ser geometry",
1979c33fcabaSmillert 		    "Enter 'd' to use the geometry based on what the disk "
19809a36aa41Ssthen 		    "itself thinks it is, or 'u' to use the geometry that "
19819a36aa41Ssthen 		    "was found in the label.",
1982c33fcabaSmillert 		    "d");
1983c33fcabaSmillert 	}
1984c33fcabaSmillert 	if (p == NULL) {
1985c33fcabaSmillert 		fputs("Command aborted\n", stderr);
1986c33fcabaSmillert 		return;
1987c33fcabaSmillert 	}
1988c33fcabaSmillert 	switch (*p) {
1989c33fcabaSmillert 	case 'd':
1990c33fcabaSmillert 	case 'D':
1991c33fcabaSmillert 		if (dgp == NULL)
1992c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
1993c33fcabaSmillert 		else {
1994c33fcabaSmillert 			lp->d_secsize = dgp->d_secsize;
1995c33fcabaSmillert 			lp->d_nsectors = dgp->d_nsectors;
1996c33fcabaSmillert 			lp->d_ntracks = dgp->d_ntracks;
1997c33fcabaSmillert 			lp->d_ncylinders = dgp->d_ncylinders;
1998c33fcabaSmillert 			lp->d_secpercyl = dgp->d_secpercyl;
199934af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(dgp));
2000c33fcabaSmillert 		}
2001c33fcabaSmillert 		break;
2002c33fcabaSmillert 	case 'u':
2003c33fcabaSmillert 	case 'U':
2004c33fcabaSmillert 		if (ugp == NULL)
2005c33fcabaSmillert 			fputs("BIOS geometry not defined.\n", stderr);
2006c33fcabaSmillert 		else {
2007c33fcabaSmillert 			lp->d_secsize = ugp->d_secsize;
2008c33fcabaSmillert 			lp->d_nsectors = ugp->d_nsectors;
2009c33fcabaSmillert 			lp->d_ntracks = ugp->d_ntracks;
2010c33fcabaSmillert 			lp->d_ncylinders = ugp->d_ncylinders;
2011c33fcabaSmillert 			lp->d_secpercyl = ugp->d_secpercyl;
201234af67a3Sotto 			DL_SETDSIZE(lp, DL_GETDSIZE(ugp));
2013c33fcabaSmillert 			if (dgp != NULL && ugp->d_secsize == dgp->d_secsize &&
2014c33fcabaSmillert 			    ugp->d_nsectors == dgp->d_nsectors &&
2015c33fcabaSmillert 			    ugp->d_ntracks == dgp->d_ntracks &&
2016c33fcabaSmillert 			    ugp->d_ncylinders == dgp->d_ncylinders &&
2017c33fcabaSmillert 			    ugp->d_secpercyl == dgp->d_secpercyl &&
201834af67a3Sotto 			    DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp))
2019c33fcabaSmillert 				fputs("Note: user geometry is the same as disk "
2020c33fcabaSmillert 				    "geometry.\n", stderr);
2021c33fcabaSmillert 		}
2022c33fcabaSmillert 		break;
2023c33fcabaSmillert 	default:
20249a36aa41Ssthen 		fputs("You must enter either 'd' or 'u'.\n", stderr);
2025c33fcabaSmillert 		break;
2026c33fcabaSmillert 	}
2027c33fcabaSmillert }
20289afbe9eeSmillert 
20299afbe9eeSmillert void
20309fdcb4d6Skrw zero_partitions(struct disklabel *lp)
20319afbe9eeSmillert {
20329afbe9eeSmillert 	int i;
20339afbe9eeSmillert 
20349afbe9eeSmillert 	for (i = 0; i < MAXPARTITIONS; i++)
20359afbe9eeSmillert 		memset(&lp->d_partitions[i], 0, sizeof(struct partition));
203634af67a3Sotto 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
20379afbe9eeSmillert }
203814192793Skrw 
203914192793Skrw u_int64_t
204014192793Skrw max_partition_size(struct disklabel *lp, int partno)
204114192793Skrw {
204214192793Skrw 	struct partition *pp = &lp->d_partitions[partno];
204314192793Skrw 	struct diskchunk *chunks;
204414192793Skrw 	u_int64_t maxsize, offset;
204514192793Skrw 	int fstype, i;
204614192793Skrw 
204714192793Skrw 	fstype = pp->p_fstype;
204814192793Skrw 	pp->p_fstype = FS_UNUSED;
204914192793Skrw 	chunks = free_chunks(lp);
205014192793Skrw 	pp->p_fstype = fstype;
205114192793Skrw 
205214192793Skrw 	offset = DL_GETPOFFSET(pp);
205314192793Skrw 	for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) {
205414192793Skrw 		if (offset < chunks[i].start || offset >= chunks[i].stop)
205514192793Skrw 			continue;
205614192793Skrw 		maxsize = chunks[i].stop - offset;
205714192793Skrw 		break;
205814192793Skrw 	}
205914192793Skrw 	return (maxsize);
206014192793Skrw }
2061