xref: /netbsd-src/sbin/disklabel/interact.c (revision ccf8c4a2ce1b9f70d6a07d7aede7488b9e1f1e85)
1*ccf8c4a2Snia /*	$NetBSD: interact.c,v 1.40 2021/11/03 14:25:39 nia Exp $	*/
272fbacb3Schristos 
372fbacb3Schristos /*
472fbacb3Schristos  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
572fbacb3Schristos  *
672fbacb3Schristos  * Redistribution and use in source and binary forms, with or without
772fbacb3Schristos  * modification, are permitted provided that the following conditions
872fbacb3Schristos  * are met:
972fbacb3Schristos  * 1. Redistributions of source code must retain the above copyright
1072fbacb3Schristos  *    notice, this list of conditions and the following disclaimer.
1172fbacb3Schristos  * 2. Redistributions in binary form must reproduce the above copyright
1272fbacb3Schristos  *    notice, this list of conditions and the following disclaimer in the
1372fbacb3Schristos  *    documentation and/or other materials provided with the distribution.
1472fbacb3Schristos  *
1572fbacb3Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1672fbacb3Schristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1772fbacb3Schristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1872fbacb3Schristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1972fbacb3Schristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2072fbacb3Schristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2172fbacb3Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2272fbacb3Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2372fbacb3Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2472fbacb3Schristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2572fbacb3Schristos  */
2672fbacb3Schristos 
270636a2feSchristos #if !defined(NO_INTERACT)
280636a2feSchristos 
291726c417Sdyoung #if HAVE_NBTOOL_CONFIG_H
301726c417Sdyoung #include "nbtool_config.h"
311726c417Sdyoung #endif
321726c417Sdyoung 
335ec7cc78Schristos #include <sys/cdefs.h>
3472fbacb3Schristos #ifndef lint
35*ccf8c4a2Snia __RCSID("$NetBSD: interact.c,v 1.40 2021/11/03 14:25:39 nia Exp $");
3672fbacb3Schristos #endif /* lint */
3772fbacb3Schristos 
385f534fcaSmrg #include <sys/param.h>
395f534fcaSmrg #define FSTYPENAMES
405f534fcaSmrg #define DKTYPENAMES
415f534fcaSmrg 
425f534fcaSmrg #include <err.h>
4372fbacb3Schristos #include <stdio.h>
4472fbacb3Schristos #include <string.h>
45b7825cc9Schristos #include <stdarg.h>
4672fbacb3Schristos #include <stdlib.h>
47b7825cc9Schristos #include <sys/ioctl.h>
481726c417Sdyoung 
491726c417Sdyoung #if HAVE_NBTOOL_CONFIG_H
50af8f0546Smatt #define	getmaxpartitions()	maxpartitions
511726c417Sdyoung #include <nbinclude/sys/disklabel.h>
521726c417Sdyoung #else
53649ae0edSchristos #include <util.h>
541726c417Sdyoung #include <sys/disklabel.h>
551726c417Sdyoung #endif /* HAVE_NBTOOL_CONFIG_H */
5672fbacb3Schristos 
5772fbacb3Schristos #include "extern.h"
5872fbacb3Schristos 
5935ccd223Slukem static void	cmd_help(struct disklabel *, char *, int);
60b7825cc9Schristos static void	cmd_adjust(struct disklabel *, char *, int);
6135ccd223Slukem static void	cmd_chain(struct disklabel *, char *, int);
6235ccd223Slukem static void	cmd_print(struct disklabel *, char *, int);
6335ccd223Slukem static void	cmd_printall(struct disklabel *, char *, int);
6435ccd223Slukem static void	cmd_info(struct disklabel *, char *, int);
6535ccd223Slukem static void	cmd_part(struct disklabel *, char *, int);
6635ccd223Slukem static void	cmd_label(struct disklabel *, char *, int);
6735ccd223Slukem static void	cmd_round(struct disklabel *, char *, int);
6835ccd223Slukem static void	cmd_name(struct disklabel *, char *, int);
6991af0d68Sjmmv static void	cmd_listfstypes(struct disklabel *, char *, int);
7035ccd223Slukem static int	runcmd(struct disklabel *, char *, int);
71b7825cc9Schristos static int	getinput(char *, const char *, ...) __printflike(2, 3);
7235ccd223Slukem static int	alphacmp(const void *, const void *);
73bb95bd59Spooka static void	defnum(struct disklabel *, char *, uint32_t);
7435ccd223Slukem static void	dumpnames(const char *, const char * const *, size_t);
750bf3480cSdholland static intmax_t	getnum(struct disklabel *, char *, intmax_t);
7672fbacb3Schristos 
7772fbacb3Schristos static int rounding = 0;	/* sector rounding */
78563aff81Schristos static int chaining = 0;	/* make partitions contiguous */
7972fbacb3Schristos 
8072fbacb3Schristos static struct cmds {
8172fbacb3Schristos 	const char *name;
8235ccd223Slukem 	void (*func)(struct disklabel *, char *, int);
8372fbacb3Schristos 	const char *help;
8472fbacb3Schristos } cmds[] = {
8572fbacb3Schristos 	{ "?",	cmd_help,	"print this menu" },
86b7825cc9Schristos 	{ "A",	cmd_adjust,	"adjust the label size to the max disk size" },
87563aff81Schristos 	{ "C",	cmd_chain,	"make partitions contiguous" },
885f534fcaSmrg 	{ "E",	cmd_printall,	"print disk label and current partition table"},
895f534fcaSmrg 	{ "I",	cmd_info,	"change label information" },
9091af0d68Sjmmv 	{ "L",	cmd_listfstypes,"list all known file system types" },
91649ae0edSchristos 	{ "N",	cmd_name,	"name the label" },
92649ae0edSchristos 	{ "P",	cmd_print,	"print current partition table" },
93649ae0edSchristos 	{ "Q",	NULL,		"quit" },
94649ae0edSchristos 	{ "R",	cmd_round,	"rounding (c)ylinders (s)ectors" },
95649ae0edSchristos 	{ "W",	cmd_label,	"write the current partition table" },
9672fbacb3Schristos 	{ NULL, NULL,		NULL }
9772fbacb3Schristos };
9872fbacb3Schristos 
9972fbacb3Schristos 
10072fbacb3Schristos static void
cmd_help(struct disklabel * lp,char * s,int fd)10135ccd223Slukem cmd_help(struct disklabel *lp, char *s, int fd)
10272fbacb3Schristos {
10372fbacb3Schristos 	struct cmds *cmd;
104649ae0edSchristos 
10572fbacb3Schristos 	for (cmd = cmds; cmd->name != NULL; cmd++)
10672fbacb3Schristos 		printf("%s\t%s\n", cmd->name, cmd->help);
107649ae0edSchristos 	printf("[a-%c]\tdefine named partition\n",
108649ae0edSchristos 	    'a' + getmaxpartitions() - 1);
10972fbacb3Schristos }
11072fbacb3Schristos 
11172fbacb3Schristos 
11272fbacb3Schristos static void
cmd_adjust(struct disklabel * lp,char * s,int fd)113b7825cc9Schristos cmd_adjust(struct disklabel *lp, char *s, int fd)
114b7825cc9Schristos {
115b7825cc9Schristos 	struct disklabel dl;
116b7825cc9Schristos 
117772a1045Schristos 	if (dk_ioctl(fd, DIOCGDEFLABEL, &dl) == -1) {
118b7825cc9Schristos 		warn("Cannot get default label");
119b7825cc9Schristos 		return;
120b7825cc9Schristos 	}
121b7825cc9Schristos 
122b7825cc9Schristos 	if (dl.d_secperunit != lp->d_secperunit) {
123b7825cc9Schristos 		char line[BUFSIZ];
124b7825cc9Schristos 		int i = getinput(line, "Adjust disklabel sector from %" PRIu32
125b7825cc9Schristos 		    " to %" PRIu32 " [n]? ", lp->d_secperunit, dl.d_secperunit);
126b7825cc9Schristos 		if (i <= 0)
127b7825cc9Schristos 			return;
128b7825cc9Schristos 		if (line[0] != 'Y' && line[0] != 'y')
129b7825cc9Schristos 			return;
130b7825cc9Schristos 		lp->d_secperunit = dl.d_secperunit;
131b7825cc9Schristos 		return;
132b7825cc9Schristos 	}
133b7825cc9Schristos 
134b7825cc9Schristos 	printf("Already at %" PRIu32 " sectors\n", dl.d_secperunit);
135b7825cc9Schristos 	return;
136b7825cc9Schristos }
137b7825cc9Schristos 
138b7825cc9Schristos static void
cmd_chain(struct disklabel * lp,char * s,int fd)13935ccd223Slukem cmd_chain(struct disklabel *lp, char *s, int fd)
140563aff81Schristos {
141563aff81Schristos 	int	i;
142563aff81Schristos 	char	line[BUFSIZ];
143563aff81Schristos 
144b7825cc9Schristos 	i = getinput(line, "Automatically adjust partitions [%s]? ",
145b7825cc9Schristos 	    chaining ? "yes" : "no");
146563aff81Schristos 	if (i <= 0)
147563aff81Schristos 		return;
148563aff81Schristos 
149563aff81Schristos 	switch (line[0]) {
150563aff81Schristos 	case 'y':
151563aff81Schristos 		chaining = 1;
152563aff81Schristos 		return;
153563aff81Schristos 	case 'n':
154563aff81Schristos 		chaining = 0;
155563aff81Schristos 		return;
156563aff81Schristos 	default:
157563aff81Schristos 		printf("Invalid answer\n");
158563aff81Schristos 		return;
159563aff81Schristos 	}
160563aff81Schristos }
161563aff81Schristos 
16235ccd223Slukem 
163563aff81Schristos static void
cmd_printall(struct disklabel * lp,char * s,int fd)16435ccd223Slukem cmd_printall(struct disklabel *lp, char *s, int fd)
1655f534fcaSmrg {
1665f534fcaSmrg 
1671c5cb88eSlukem 	showinfo(stdout, lp, specname);
1681c5cb88eSlukem 	showpartitions(stdout, lp, Cflag);
1695f534fcaSmrg }
1705f534fcaSmrg 
17135ccd223Slukem 
1725f534fcaSmrg static void
cmd_print(struct disklabel * lp,char * s,int fd)17335ccd223Slukem cmd_print(struct disklabel *lp, char *s, int fd)
17472fbacb3Schristos {
17535ccd223Slukem 
1761c5cb88eSlukem 	showpartitions(stdout, lp, Cflag);
17772fbacb3Schristos }
17872fbacb3Schristos 
17935ccd223Slukem 
1805f534fcaSmrg static void
cmd_info(struct disklabel * lp,char * s,int fd)18135ccd223Slukem cmd_info(struct disklabel *lp, char *s, int fd)
1825f534fcaSmrg {
1835f534fcaSmrg 	char	line[BUFSIZ];
1845f534fcaSmrg 	int	v, i;
1855f534fcaSmrg 	u_int32_t u;
1865f534fcaSmrg 
1875f534fcaSmrg 	printf("# Current values:\n");
1881c5cb88eSlukem 	showinfo(stdout, lp, specname);
1895f534fcaSmrg 
1904c8c8685Slukem 	/* d_type */
1915f534fcaSmrg 	for (;;) {
1924c8c8685Slukem 		i = lp->d_type;
1934c8c8685Slukem 		if (i < 0 || i >= DKMAXTYPES)
1944c8c8685Slukem 			i = 0;
195b7825cc9Schristos 		i = getinput(line, "Disk type [%s]: ", dktypenames[i]);
1964c8c8685Slukem 		if (i == -1)
1974c8c8685Slukem 			return;
1984c8c8685Slukem 		else if (i == 0)
1995f534fcaSmrg 			break;
2004c8c8685Slukem 		if (!strcmp(line, "?")) {
2014c8c8685Slukem 			dumpnames("Supported disk types", dktypenames,
2024c8c8685Slukem 			    DKMAXTYPES);
2034c8c8685Slukem 			continue;
2044c8c8685Slukem 		}
2054c8c8685Slukem 		for (i = 0; i < DKMAXTYPES; i++) {
2064c8c8685Slukem 			if (!strcasecmp(dktypenames[i], line)) {
2074c8c8685Slukem 				lp->d_type = i;
2085f534fcaSmrg 				goto done_typename;
2095f534fcaSmrg 			}
2104c8c8685Slukem 		}
2115f534fcaSmrg 		v = atoi(line);
2125f534fcaSmrg 		if ((unsigned)v >= DKMAXTYPES) {
2134c8c8685Slukem 			warnx("Unknown disk type: %s", line);
2145f534fcaSmrg 			continue;
2155f534fcaSmrg 		}
2165f534fcaSmrg 		lp->d_type = v;
2175f534fcaSmrg  done_typename:
2185f534fcaSmrg 		break;
2195f534fcaSmrg 	}
2205f534fcaSmrg 
2214c8c8685Slukem 	/* d_typename */
222b7825cc9Schristos 	i = getinput(line, "Disk name [%.*s]: ",
2234c8c8685Slukem 	    (int) sizeof(lp->d_typename), lp->d_typename);
2244c8c8685Slukem 	if (i == -1)
2254c8c8685Slukem 		return;
2264c8c8685Slukem 	else if (i == 1)
2274c8c8685Slukem 		(void) strncpy(lp->d_typename, line, sizeof(lp->d_typename));
2284c8c8685Slukem 
2295f534fcaSmrg 	/* d_packname */
2305f534fcaSmrg 	cmd_name(lp, s, fd);
2315f534fcaSmrg 
2325f534fcaSmrg 	/* d_npartitions */
2335f534fcaSmrg 	for (;;) {
234b7825cc9Schristos 		i = getinput(line, "Number of partitions [%" PRIu16 "]: ",
235b7825cc9Schristos 		    lp->d_npartitions);
2364c8c8685Slukem 		if (i == -1)
2374c8c8685Slukem 			return;
2384c8c8685Slukem 		else if (i == 0)
2395f534fcaSmrg 			break;
24063df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
2414c8c8685Slukem 			printf("Invalid number of partitions `%s'\n", line);
2425f534fcaSmrg 			continue;
2435f534fcaSmrg 		}
2445f534fcaSmrg 		lp->d_npartitions = u;
2455f534fcaSmrg 		break;
2465f534fcaSmrg 	}
2475f534fcaSmrg 
2485f534fcaSmrg 	/* d_secsize */
2495f534fcaSmrg 	for (;;) {
250b7825cc9Schristos 		i = getinput(line, "Sector size (bytes) [%" PRIu32 "]: ",
251b7825cc9Schristos 		    lp->d_secsize);
2524c8c8685Slukem 		if (i == -1)
2534c8c8685Slukem 			return;
2544c8c8685Slukem 		else if (i == 0)
2555f534fcaSmrg 			break;
25663df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
2575f534fcaSmrg 			printf("Invalid sector size `%s'\n", line);
2585f534fcaSmrg 			continue;
2595f534fcaSmrg 		}
2605f534fcaSmrg 		lp->d_secsize = u;
2615f534fcaSmrg 		break;
2625f534fcaSmrg 	}
2635f534fcaSmrg 
2645f534fcaSmrg 	/* d_nsectors */
2655f534fcaSmrg 	for (;;) {
266b7825cc9Schristos 		i = getinput(line, "Number of sectors per track [%" PRIu32
267b7825cc9Schristos 		    "]: ", lp->d_nsectors);
2684c8c8685Slukem 		if (i == -1)
2694c8c8685Slukem 			return;
2704c8c8685Slukem 		else if (i == 0)
2715f534fcaSmrg 			break;
27263df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
2734c8c8685Slukem 			printf("Invalid number of sectors `%s'\n", line);
2745f534fcaSmrg 			continue;
2755f534fcaSmrg 		}
2765f534fcaSmrg 		lp->d_nsectors = u;
2775f534fcaSmrg 		break;
2785f534fcaSmrg 	}
2795f534fcaSmrg 
2805f534fcaSmrg 	/* d_ntracks */
2815f534fcaSmrg 	for (;;) {
282b7825cc9Schristos 		i = getinput(line, "Number of tracks per cylinder [%" PRIu32
283b7825cc9Schristos 		    "]: ", lp->d_ntracks);
2844c8c8685Slukem 		if (i == -1)
2854c8c8685Slukem 			return;
2864c8c8685Slukem 		else if (i == 0)
2875f534fcaSmrg 			break;
28863df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
2895f534fcaSmrg 			printf("Invalid number of tracks `%s'\n", line);
2905f534fcaSmrg 			continue;
2915f534fcaSmrg 		}
2925f534fcaSmrg 		lp->d_ntracks = u;
2935f534fcaSmrg 		break;
2945f534fcaSmrg 	}
2955f534fcaSmrg 
2965f534fcaSmrg 	/* d_secpercyl */
2975f534fcaSmrg 	for (;;) {
298b7825cc9Schristos 		i = getinput(line, "Number of sectors/cylinder [%" PRIu32 "]: ",
299b7825cc9Schristos 		    lp->d_secpercyl);
3004c8c8685Slukem 		if (i == -1)
3014c8c8685Slukem 			return;
3024c8c8685Slukem 		else if (i == 0)
3035f534fcaSmrg 			break;
30463df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3054c8c8685Slukem 			printf("Invalid number of sector/cylinder `%s'\n",
3064c8c8685Slukem 			    line);
3075f534fcaSmrg 			continue;
3085f534fcaSmrg 		}
3095f534fcaSmrg 		lp->d_secpercyl = u;
3105f534fcaSmrg 		break;
3115f534fcaSmrg 	}
3125f534fcaSmrg 
3135f534fcaSmrg 	/* d_ncylinders */
3145f534fcaSmrg 	for (;;) {
315b7825cc9Schristos 		i = getinput(line, "Total number of cylinders [%" PRIu32 "]: ",
316b7825cc9Schristos 		    lp->d_ncylinders);
3174c8c8685Slukem 		if (i == -1)
3184c8c8685Slukem 			return;
3194c8c8685Slukem 		else if (i == 0)
3205f534fcaSmrg 			break;
32163df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3225f534fcaSmrg 			printf("Invalid sector size `%s'\n", line);
3235f534fcaSmrg 			continue;
3245f534fcaSmrg 		}
3255f534fcaSmrg 		lp->d_ncylinders = u;
3265f534fcaSmrg 		break;
3275f534fcaSmrg 	}
3285f534fcaSmrg 
3295f534fcaSmrg 	/* d_secperunit */
3305f534fcaSmrg 	for (;;) {
331b7825cc9Schristos 		i = getinput(line, "Total number of sectors [%" PRIu32 "]: ",
332b7825cc9Schristos 		    lp->d_secperunit);
3334c8c8685Slukem 		if (i == -1)
3344c8c8685Slukem 			return;
3354c8c8685Slukem 		else if (i == 0)
3365f534fcaSmrg 			break;
33763df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3384c8c8685Slukem 			printf("Invalid number of sectors `%s'\n", line);
3395f534fcaSmrg 			continue;
3405f534fcaSmrg 		}
3415f534fcaSmrg 		lp->d_secperunit = u;
3425f534fcaSmrg 		break;
3435f534fcaSmrg 	}
3445f534fcaSmrg 
3455f534fcaSmrg 	/* d_rpm */
3465f534fcaSmrg 
3475f534fcaSmrg 	/* d_interleave */
3485f534fcaSmrg 	for (;;) {
349b7825cc9Schristos 		i = getinput(line, "Hardware sectors interleave [%" PRIu16
350b7825cc9Schristos 		    "]: ", lp->d_interleave);
3514c8c8685Slukem 		if (i == -1)
3524c8c8685Slukem 			return;
3534c8c8685Slukem 		else if (i == 0)
3545f534fcaSmrg 			break;
35563df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3564c8c8685Slukem 			printf("Invalid sector interleave `%s'\n", line);
3575f534fcaSmrg 			continue;
3585f534fcaSmrg 		}
3595f534fcaSmrg 		lp->d_interleave = u;
3605f534fcaSmrg 		break;
3615f534fcaSmrg 	}
3625f534fcaSmrg 
3635f534fcaSmrg 	/* d_trackskew */
3645f534fcaSmrg 	for (;;) {
365b7825cc9Schristos 		i = getinput(line, "Sector 0 skew, per track [%" PRIu16 "]: ",
366b7825cc9Schristos 		    lp->d_trackskew);
3674c8c8685Slukem 		if (i == -1)
3684c8c8685Slukem 			return;
3694c8c8685Slukem 		else if (i == 0)
3705f534fcaSmrg 			break;
37163df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3724c8c8685Slukem 			printf("Invalid track sector skew `%s'\n", line);
3735f534fcaSmrg 			continue;
3745f534fcaSmrg 		}
3755f534fcaSmrg 		lp->d_trackskew = u;
3765f534fcaSmrg 		break;
3775f534fcaSmrg 	}
3785f534fcaSmrg 
3795f534fcaSmrg 	/* d_cylskew */
3805f534fcaSmrg 	for (;;) {
381b7825cc9Schristos 		i = getinput(line, "Sector 0 skew, per cylinder [%" PRIu16
382b7825cc9Schristos 		    "]: ", lp->d_cylskew);
3834c8c8685Slukem 		if (i == -1)
3844c8c8685Slukem 			return;
3854c8c8685Slukem 		else if (i == 0)
3865f534fcaSmrg 			break;
38763df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
3884c8c8685Slukem 			printf("Invalid cylinder sector `%s'\n", line);
3895f534fcaSmrg 			continue;
3905f534fcaSmrg 		}
3915f534fcaSmrg 		lp->d_cylskew = u;
3925f534fcaSmrg 		break;
3935f534fcaSmrg 	}
3945f534fcaSmrg 
3955f534fcaSmrg 	/* d_headswitch */
3965f534fcaSmrg 	for (;;) {
397b7825cc9Schristos 		i = getinput(line, "Head switch time (usec) [%" PRIu32 "]: ",
398b7825cc9Schristos 		    lp->d_headswitch);
3994c8c8685Slukem 		if (i == -1)
4004c8c8685Slukem 			return;
4014c8c8685Slukem 		else if (i == 0)
4025f534fcaSmrg 			break;
40363df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
4044c8c8685Slukem 			printf("Invalid head switch time `%s'\n", line);
4055f534fcaSmrg 			continue;
4065f534fcaSmrg 		}
4075f534fcaSmrg 		lp->d_headswitch = u;
4085f534fcaSmrg 		break;
4095f534fcaSmrg 	}
4105f534fcaSmrg 
4115f534fcaSmrg 	/* d_trkseek */
4125f534fcaSmrg 	for (;;) {
413b7825cc9Schristos 		i = getinput(line, "Track seek time (usec) [%" PRIu32 "]:",
414b7825cc9Schristos 		    lp->d_trkseek);
4154c8c8685Slukem 		if (i == -1)
4164c8c8685Slukem 			return;
4174c8c8685Slukem 		else if (i == 0)
4185f534fcaSmrg 			break;
41963df928bSapb 		if (sscanf(line, "%" SCNu32, &u) != 1) {
4204c8c8685Slukem 			printf("Invalid track seek time `%s'\n", line);
4215f534fcaSmrg 			continue;
4225f534fcaSmrg 		}
4235f534fcaSmrg 		lp->d_trkseek = u;
4245f534fcaSmrg 		break;
4255f534fcaSmrg 	}
4265f534fcaSmrg }
42772fbacb3Schristos 
42835ccd223Slukem 
42972fbacb3Schristos static void
cmd_name(struct disklabel * lp,char * s,int fd)43035ccd223Slukem cmd_name(struct disklabel *lp, char *s, int fd)
43172fbacb3Schristos {
43272fbacb3Schristos 	char	line[BUFSIZ];
4334c8c8685Slukem 	int	i;
43472fbacb3Schristos 
435b7825cc9Schristos 	i = getinput(line, "Label name [%.*s]: ",
4364c8c8685Slukem 	    (int) sizeof(lp->d_packname), lp->d_packname);
43772fbacb3Schristos 	if (i <= 0)
43872fbacb3Schristos 		return;
43972fbacb3Schristos 	(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
44072fbacb3Schristos }
44172fbacb3Schristos 
44235ccd223Slukem 
44372fbacb3Schristos static void
cmd_round(struct disklabel * lp,char * s,int fd)44435ccd223Slukem cmd_round(struct disklabel *lp, char *s, int fd)
44572fbacb3Schristos {
44672fbacb3Schristos 	int	i;
44772fbacb3Schristos 	char	line[BUFSIZ];
44872fbacb3Schristos 
449b7825cc9Schristos 	i = getinput(line, "Rounding [%s]: ", rounding ? "cylinders" :
450b7825cc9Schristos 	    "sectors");
45172fbacb3Schristos 	if (i <= 0)
45272fbacb3Schristos 		return;
45372fbacb3Schristos 
45472fbacb3Schristos 	switch (line[0]) {
45572fbacb3Schristos 	case 'c':
4568dba43fbSchristos 	case 'C':
45772fbacb3Schristos 		rounding = 1;
45872fbacb3Schristos 		return;
45972fbacb3Schristos 	case 's':
4608dba43fbSchristos 	case 'S':
46172fbacb3Schristos 		rounding = 0;
46272fbacb3Schristos 		return;
46372fbacb3Schristos 	default:
46472fbacb3Schristos 		printf("Rounding can be (c)ylinders or (s)ectors\n");
46572fbacb3Schristos 		return;
46672fbacb3Schristos 	}
46772fbacb3Schristos }
46872fbacb3Schristos 
46935ccd223Slukem 
47072fbacb3Schristos static void
cmd_part(struct disklabel * lp,char * s,int fd)47135ccd223Slukem cmd_part(struct disklabel *lp, char *s, int fd)
47272fbacb3Schristos {
47372fbacb3Schristos 	int	i;
4740bf3480cSdholland 	intmax_t im;
47572fbacb3Schristos 	char	line[BUFSIZ];
47672fbacb3Schristos 	char	def[BUFSIZ];
47735ccd223Slukem 	int	part;
47879569512Schristos 	struct partition *p, ps;
47972fbacb3Schristos 
48035ccd223Slukem 	part = s[0] - 'a';
48135ccd223Slukem 	p = &lp->d_partitions[part];
4825a6005a0Schristos 	if (part >= lp->d_npartitions)
48372fbacb3Schristos 		lp->d_npartitions = part + 1;
48472fbacb3Schristos 
48579569512Schristos 	(void)memcpy(&ps, p, sizeof(ps));
48679569512Schristos 
48772fbacb3Schristos 	for (;;) {
4884c8c8685Slukem 		i = p->p_fstype;
4894c8c8685Slukem 		if (i < 0 || i >= FSMAXTYPES)
4904c8c8685Slukem 			i = 0;
491b7825cc9Schristos 		i = getinput(line, "Filesystem type [%s]: ", fstypenames[i]);
4924c8c8685Slukem 		if (i == -1)
4934c8c8685Slukem 			return;
4944c8c8685Slukem 		else if (i == 0)
49572fbacb3Schristos 			break;
4964c8c8685Slukem 		if (!strcmp(line, "?")) {
4974c8c8685Slukem 			dumpnames("Supported file system types",
4984c8c8685Slukem 			    fstypenames, FSMAXTYPES);
49972fbacb3Schristos 			continue;
50072fbacb3Schristos 		}
5014c8c8685Slukem 		for (i = 0; i < FSMAXTYPES; i++)
5024c8c8685Slukem 			if (!strcasecmp(line, fstypenames[i])) {
50372fbacb3Schristos 				p->p_fstype = i;
5044c8c8685Slukem 				goto done_typename;
5054c8c8685Slukem 			}
5064c8c8685Slukem 		printf("Invalid file system typename `%s'\n", line);
5074c8c8685Slukem 		continue;
5084c8c8685Slukem  done_typename:
50972fbacb3Schristos 		break;
51072fbacb3Schristos 	}
51172fbacb3Schristos 	for (;;) {
51235ccd223Slukem 		defnum(lp, def, p->p_offset);
513b7825cc9Schristos 		i = getinput(line, "Start offset ('x' to start after partition"
514b7825cc9Schristos 		" 'x') [%s]: ", def);
5154c8c8685Slukem 		if (i == -1)
5164c8c8685Slukem 			return;
5174c8c8685Slukem 		else if (i == 0)
51872fbacb3Schristos 			break;
519256b6fecSjdc 		if (line[1] == '\0' &&
520256b6fecSjdc 	    		line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
521256b6fecSjdc 			struct partition *cp = lp->d_partitions;
522256b6fecSjdc 
523256b6fecSjdc 			if ((cp[line[0] - 'a'].p_offset +
524256b6fecSjdc 			    cp[line[0] - 'a'].p_size) >= lp->d_secperunit) {
525256b6fecSjdc 				printf("Bad offset `%s'\n", line);
526256b6fecSjdc 				continue;
527256b6fecSjdc 			} else {
528256b6fecSjdc 				p->p_offset = cp[line[0] - 'a'].p_offset +
529256b6fecSjdc 				    cp[line[0] - 'a'].p_size;
530256b6fecSjdc 			}
531256b6fecSjdc 		} else {
5320bf3480cSdholland 			if ((im = getnum(lp, line, 0)) == -1 || im < 0) {
53372fbacb3Schristos 				printf("Bad offset `%s'\n", line);
53472fbacb3Schristos 				continue;
5350bf3480cSdholland 			} else if (im > 0xffffffffLL ||
5360bf3480cSdholland 				   (uint32_t)im > lp->d_secperunit) {
53797a9e023Sgrant 				printf("Offset `%s' out of range\n", line);
53897a9e023Sgrant 				continue;
53972fbacb3Schristos 			}
5400bf3480cSdholland 			p->p_offset = (uint32_t)im;
541256b6fecSjdc 		}
54272fbacb3Schristos 		break;
54372fbacb3Schristos 	}
54472fbacb3Schristos 	for (;;) {
54535ccd223Slukem 		defnum(lp, def, p->p_size);
546b7825cc9Schristos 		i = getinput(line, "Partition size ('$' for all remaining) "
547b7825cc9Schristos 		    "[%s]: ", def);
5484c8c8685Slukem 		if (i == -1)
5494c8c8685Slukem 			return;
5504c8c8685Slukem 		else if (i == 0)
55172fbacb3Schristos 			break;
5520bf3480cSdholland 		if ((im = getnum(lp, line, lp->d_secperunit - p->p_offset))
553669feec4Sabs 		    == -1) {
55472fbacb3Schristos 			printf("Bad size `%s'\n", line);
55572fbacb3Schristos 			continue;
5560bf3480cSdholland 		} else if (im > 0xffffffffLL ||
5570bf3480cSdholland 			   (im + p->p_offset) > lp->d_secperunit) {
55897a9e023Sgrant 			printf("Size `%s' out of range\n", line);
55997a9e023Sgrant 			continue;
56072fbacb3Schristos 		}
5610bf3480cSdholland 		p->p_size = im;
56272fbacb3Schristos 		break;
56372fbacb3Schristos 	}
564563aff81Schristos 
565256b6fecSjdc 	if (memcmp(&ps, p, sizeof(ps)))
566256b6fecSjdc 		showpartition(stdout, lp, part, Cflag);
567563aff81Schristos 	if (chaining) {
56879569512Schristos 		int offs = -1;
56979569512Schristos 		struct partition *cp = lp->d_partitions;
57079569512Schristos 		for (i = 0; i < lp->d_npartitions; i++) {
57179569512Schristos 			if (cp[i].p_fstype != FS_UNUSED) {
57207f76885Slukem 				if (offs != -1 && cp[i].p_offset != (uint32_t)offs) {
57379569512Schristos 					cp[i].p_offset = offs;
574256b6fecSjdc 					showpartition(stdout, lp, i, Cflag);
575256b6fecSjdc 					}
57679569512Schristos 				offs = cp[i].p_offset + cp[i].p_size;
577563aff81Schristos 			}
578563aff81Schristos 		}
579563aff81Schristos 	}
58072fbacb3Schristos }
58172fbacb3Schristos 
58272fbacb3Schristos 
58372fbacb3Schristos static void
cmd_label(struct disklabel * lp,char * s,int fd)58435ccd223Slukem cmd_label(struct disklabel *lp, char *s, int fd)
58572fbacb3Schristos {
58672fbacb3Schristos 	char	line[BUFSIZ];
58772fbacb3Schristos 	int	i;
58872fbacb3Schristos 
589b7825cc9Schristos 	i = getinput(line, "Label disk [n]?");
590b755b885Sabs 	if (i <= 0 || (*line != 'y' && *line != 'Y') )
59172fbacb3Schristos 		return;
59272fbacb3Schristos 
59372fbacb3Schristos 	if (checklabel(lp) != 0) {
59472fbacb3Schristos 		printf("Label not written\n");
59572fbacb3Schristos 		return;
59672fbacb3Schristos 	}
59772fbacb3Schristos 
59865151c95Sdsl 	if (writelabel(fd, lp) != 0) {
5998daf1590Senami 		printf("Label not written\n");
60072fbacb3Schristos 		return;
60172fbacb3Schristos 	}
60272fbacb3Schristos 	printf("Label written\n");
60372fbacb3Schristos }
60472fbacb3Schristos 
60572fbacb3Schristos 
60691af0d68Sjmmv static void
cmd_listfstypes(struct disklabel * lp,char * s,int fd)60791af0d68Sjmmv cmd_listfstypes(struct disklabel *lp, char *s, int fd)
60891af0d68Sjmmv {
60991af0d68Sjmmv 
61091af0d68Sjmmv 	(void)list_fs_types();
61191af0d68Sjmmv }
61291af0d68Sjmmv 
61391af0d68Sjmmv 
61472fbacb3Schristos static int
runcmd(struct disklabel * lp,char * line,int fd)61535ccd223Slukem runcmd(struct disklabel *lp, char *line, int fd)
61672fbacb3Schristos {
61772fbacb3Schristos 	struct cmds *cmd;
61872fbacb3Schristos 
61972fbacb3Schristos 	for (cmd = cmds; cmd->name != NULL; cmd++)
62072fbacb3Schristos 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
62172fbacb3Schristos 			if (cmd->func == NULL)
62272fbacb3Schristos 				return -1;
62372fbacb3Schristos 			(*cmd->func)(lp, line, fd);
6245ec7cc78Schristos 			return 0;
62572fbacb3Schristos 		}
626649ae0edSchristos 
627649ae0edSchristos 	if (line[1] == '\0' &&
628649ae0edSchristos 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
629649ae0edSchristos 		cmd_part(lp, line, fd);
6305ec7cc78Schristos 		return 0;
631649ae0edSchristos 	}
632649ae0edSchristos 
63372fbacb3Schristos 	printf("Unknown command %s\n", line);
6345ec7cc78Schristos 	return 1;
63572fbacb3Schristos }
63672fbacb3Schristos 
63772fbacb3Schristos 
63872fbacb3Schristos static int
getinput(char * line,const char * prompt,...)639b7825cc9Schristos getinput(char *line, const char *prompt, ...)
64072fbacb3Schristos {
64135ccd223Slukem 
64272fbacb3Schristos 	for (;;) {
643b7825cc9Schristos 		va_list ap;
644b7825cc9Schristos 		va_start(ap, prompt);
645b7825cc9Schristos 		vprintf(prompt, ap);
646b7825cc9Schristos 		va_end(ap);
64772fbacb3Schristos 
64872fbacb3Schristos 		if (fgets(line, BUFSIZ, stdin) == NULL)
64972fbacb3Schristos 			return -1;
650b7825cc9Schristos 		if (line[0] == '\n' || line[0] == '\0')
65172fbacb3Schristos 			return 0;
65272fbacb3Schristos 		else {
65372fbacb3Schristos 			char *p;
65472fbacb3Schristos 
65572fbacb3Schristos 			if ((p = strrchr(line, '\n')) != NULL)
65672fbacb3Schristos 				*p = '\0';
65772fbacb3Schristos 			return 1;
65872fbacb3Schristos 		}
65972fbacb3Schristos 	}
66072fbacb3Schristos }
66172fbacb3Schristos 
6624c8c8685Slukem static int
alphacmp(const void * a,const void * b)66335ccd223Slukem alphacmp(const void *a, const void *b)
6644c8c8685Slukem {
6654c8c8685Slukem 
6662c6eadc9Schristos 	return (strcasecmp(*(const char * const*)a, *(const char * const*)b));
6674c8c8685Slukem }
6684c8c8685Slukem 
6694c8c8685Slukem 
6704c8c8685Slukem static void
dumpnames(const char * prompt,const char * const * olist,size_t numentries)67135ccd223Slukem dumpnames(const char *prompt, const char * const *olist, size_t numentries)
6724c8c8685Slukem {
67307f76885Slukem 	int	w;
67407f76885Slukem 	size_t	i, entry, lines;
67507f76885Slukem 	int	columns, width;
6764c8c8685Slukem 	const char *p;
677*ccf8c4a2Snia 	const char **list = NULL;
6784c8c8685Slukem 
679*ccf8c4a2Snia 	if (reallocarr(&list, numentries, sizeof(char *)) != 0)
680*ccf8c4a2Snia 		err(1, "reallocarr");
6814c8c8685Slukem 	width = 0;
6824c8c8685Slukem 	printf("%s:\n", prompt);
6834c8c8685Slukem 	for (i = 0; i < numentries; i++) {
6844c8c8685Slukem 		list[i] = olist[i];
6854c8c8685Slukem 		w = strlen(list[i]);
6864c8c8685Slukem 		if (w > width)
6874c8c8685Slukem 			width = w;
6884c8c8685Slukem 	}
6894c8c8685Slukem #if 0
6904c8c8685Slukem 	for (i = 0; i < numentries; i++)
6914c8c8685Slukem 		printf("%s%s", i == 0 ? "" : ", ", list[i]);
6924c8c8685Slukem 	puts("");
6934c8c8685Slukem #endif
69480644903Slukem 	(void)qsort(list, numentries, sizeof(char *), alphacmp);
6954c8c8685Slukem 	width++;		/* want two spaces between items */
6964c8c8685Slukem 	width = (width + 8) &~ 7;
6974c8c8685Slukem 
6984c8c8685Slukem #define ttywidth 72
6994c8c8685Slukem 	columns = ttywidth / width;
7004c8c8685Slukem #undef ttywidth
7014c8c8685Slukem 	if (columns == 0)
7024c8c8685Slukem 		columns = 1;
7034c8c8685Slukem 	lines = (numentries + columns - 1) / columns;
70457c63d89Sdsl 	/* Output sorted by columns */
7054c8c8685Slukem 	for (i = 0; i < lines; i++) {
7064c8c8685Slukem 		putc('\t', stdout);
70757c63d89Sdsl 		entry = i;
70857c63d89Sdsl 		for (;;) {
70957c63d89Sdsl 			p = list[entry];
7104c8c8685Slukem 			fputs(p, stdout);
71157c63d89Sdsl 			entry += lines;
71257c63d89Sdsl 			if (entry >= numentries)
7134c8c8685Slukem 				break;
7144c8c8685Slukem 			w = strlen(p);
7154c8c8685Slukem 			while (w < width) {
7164c8c8685Slukem 				w = (w + 8) & ~7;
7174c8c8685Slukem 				putc('\t', stdout);
7184c8c8685Slukem 			}
7194c8c8685Slukem 		}
72057c63d89Sdsl 		putc('\n', stdout);
7214c8c8685Slukem 	}
7224c8c8685Slukem 	free(list);
7234c8c8685Slukem }
7244c8c8685Slukem 
72572fbacb3Schristos 
72672fbacb3Schristos static void
defnum(struct disklabel * lp,char * buf,uint32_t size)727bb95bd59Spooka defnum(struct disklabel *lp, char *buf, uint32_t size)
72872fbacb3Schristos {
72935ccd223Slukem 
73063df928bSapb 	(void) snprintf(buf, BUFSIZ, "%.40gc, %" PRIu32 "s, %.40gM",
73172fbacb3Schristos 	    size / (float) lp->d_secpercyl,
73272fbacb3Schristos 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
73372fbacb3Schristos }
73472fbacb3Schristos 
73572fbacb3Schristos 
7360bf3480cSdholland static intmax_t
getnum(struct disklabel * lp,char * buf,intmax_t defaultval)7370bf3480cSdholland getnum(struct disklabel *lp, char *buf, intmax_t defaultval)
73872fbacb3Schristos {
73972fbacb3Schristos 	char	*ep;
740669feec4Sabs 	double	 d;
7410bf3480cSdholland 	intmax_t rv;
74272fbacb3Schristos 
7430bf3480cSdholland 	if (defaultval && buf[0] == '$' && buf[1] == 0)
7440bf3480cSdholland 		return defaultval;
745669feec4Sabs 
746669feec4Sabs 	d = strtod(buf, &ep);
74772fbacb3Schristos 	if (buf == ep)
74872fbacb3Schristos 		return -1;
74972fbacb3Schristos 
75035ccd223Slukem #define ROUND(a)	((((a) / lp->d_secpercyl) + \
75135ccd223Slukem 		 	 (((a) % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl)
75272fbacb3Schristos 
75372fbacb3Schristos 	switch (*ep) {
75472fbacb3Schristos 	case '\0':
75572fbacb3Schristos 	case 's':
7568dba43fbSchristos 	case 'S':
7570bf3480cSdholland 		rv = (intmax_t) d;
75872fbacb3Schristos 		break;
75972fbacb3Schristos 
76072fbacb3Schristos 	case 'c':
7618dba43fbSchristos 	case 'C':
7620bf3480cSdholland 		rv = (intmax_t) (d * lp->d_secpercyl);
76372fbacb3Schristos 		break;
76472fbacb3Schristos 
7658dba43fbSchristos 	case 'k':
7668dba43fbSchristos 	case 'K':
7670bf3480cSdholland 		rv =  (intmax_t) (d * 1024 / lp->d_secsize);
7688dba43fbSchristos 		break;
7698dba43fbSchristos 
7704c8c8685Slukem 	case 'm':
77172fbacb3Schristos 	case 'M':
7720bf3480cSdholland 		rv =  (intmax_t) (d * 1024 * 1024 / lp->d_secsize);
77372fbacb3Schristos 		break;
77472fbacb3Schristos 
7758dba43fbSchristos 	case 'g':
7768dba43fbSchristos 	case 'G':
7770bf3480cSdholland 		rv =  (intmax_t) (d * 1024 * 1024 * 1024 / lp->d_secsize);
7788dba43fbSchristos 		break;
7798dba43fbSchristos 
7808dba43fbSchristos 	case 't':
7818dba43fbSchristos 	case 'T':
7820bf3480cSdholland 		rv =  (intmax_t) (d * 1024 * 1024 * 1024 * 1024 / lp->d_secsize);
7838dba43fbSchristos 		break;
7848dba43fbSchristos 
78572fbacb3Schristos 	default:
78672fbacb3Schristos 		printf("Unit error %c\n", *ep);
7878dba43fbSchristos 		printf("Valid units: (S)ectors, (C)ylinders, (K)ilo, (M)ega, "
7888dba43fbSchristos 		    "(G)iga, (T)era");
78972fbacb3Schristos 		return -1;
79072fbacb3Schristos 	}
79172fbacb3Schristos 
79272fbacb3Schristos 	if (rounding)
79372fbacb3Schristos 		return ROUND(rv);
79472fbacb3Schristos 	else
79572fbacb3Schristos 		return rv;
79672fbacb3Schristos }
79772fbacb3Schristos 
79872fbacb3Schristos 
79972fbacb3Schristos void
interact(struct disklabel * lp,int fd)80035ccd223Slukem interact(struct disklabel *lp, int fd)
80172fbacb3Schristos {
80272fbacb3Schristos 	char	line[BUFSIZ];
80372fbacb3Schristos 
804b861177eSabs 	puts("Enter '?' for help");
80572fbacb3Schristos 	for (;;) {
806b7825cc9Schristos 		int i = getinput(line, "partition>");
807b7825cc9Schristos 		if (i == -1)
80872fbacb3Schristos 			return;
809b7825cc9Schristos 		if (i == 0)
810b7825cc9Schristos 			continue;
81135ccd223Slukem 		if (runcmd(lp, line, fd) == -1)
81272fbacb3Schristos 			return;
81372fbacb3Schristos 	}
81472fbacb3Schristos }
8150636a2feSchristos 
8160636a2feSchristos #endif /* !NO_INTERACT */
817