xref: /netbsd-src/sbin/disklabel/interact.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: interact.c,v 1.4 1997/03/18 21:26:44 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Christos Zoulas.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static char rcsid[] = "$NetBSD: interact.c,v 1.4 1997/03/18 21:26:44 christos Exp $";
34 #endif /* lint */
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <util.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #define DKTYPENAMES
43 #include <sys/disklabel.h>
44 
45 #include "extern.h"
46 
47 static void cmd_help __P((struct disklabel *, char *, int));
48 static void cmd_print __P((struct disklabel *, char *, int));
49 static void cmd_part __P((struct disklabel *, char *, int));
50 static void cmd_label __P((struct disklabel *, char *, int));
51 static void cmd_round __P((struct disklabel *, char *, int));
52 static void cmd_name __P((struct disklabel *, char *, int));
53 static int runcmd __P((char *, struct disklabel *, int));
54 static int getinput __P((const char *, const char *, const char *, char *));
55 static void defnum __P((char *, struct disklabel *, int));
56 static int getnum __P((char *, struct disklabel *));
57 static void deffstypename __P((char *, int));
58 static int getfstypename __P((const char *));
59 
60 static int rounding = 0;	/* sector rounding */
61 
62 static struct cmds {
63 	const char *name;
64 	void (*func) __P((struct disklabel *, char *, int));
65 	const char *help;
66 } cmds[] = {
67 	{ "?",	cmd_help,	"print this menu" },
68 	{ "N",	cmd_name,	"name the label" },
69 	{ "P",	cmd_print,	"print current partition table" },
70 	{ "Q",	NULL,		"quit" },
71 	{ "R",	cmd_round,	"rounding (c)ylinders (s)ectors" },
72 	{ "W",	cmd_label,	"write the current partition table" },
73 	{ NULL, NULL,		NULL }
74 };
75 
76 
77 
78 static void
79 cmd_help(lp, s, fd)
80 	struct disklabel *lp;
81 	char *s;
82 	int fd;
83 {
84 	struct cmds *cmd;
85 
86 	for (cmd = cmds; cmd->name != NULL; cmd++)
87 		printf("%s\t%s\n", cmd->name, cmd->help);
88 	printf("[a-%c]\tdefine named partition\n",
89 	    'a' + getmaxpartitions() - 1);
90 }
91 
92 
93 static void
94 cmd_print(lp, s, fd)
95 	struct disklabel *lp;
96 	char *s;
97 	int fd;
98 {
99 	display(stdout, lp);
100 }
101 
102 
103 static void
104 cmd_name(lp, s, fd)
105 	struct disklabel *lp;
106 	char *s;
107 	int fd;
108 {
109 	char line[BUFSIZ];
110 	int i = getinput(":", "Label name", lp->d_packname, line);
111 
112 	if (i <= 0)
113 		return;
114 	(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
115 }
116 
117 
118 static void
119 cmd_round(lp, s, fd)
120 	struct disklabel *lp;
121 	char *s;
122 	int fd;
123 {
124 	int i;
125 	char line[BUFSIZ];
126 
127 	i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
128 
129 	if (i <= 0)
130 		return;
131 
132 	switch (line[0]) {
133 	case 'c':
134 		rounding = 1;
135 		return;
136 	case 's':
137 		rounding = 0;
138 		return;
139 	default:
140 		printf("Rounding can be (c)ylinders or (s)ectors\n");
141 		return;
142 	}
143 }
144 
145 
146 static void
147 cmd_part(lp, s, fd)
148 	struct disklabel *lp;
149 	char *s;
150 	int fd;
151 {
152 	int i;
153 	char line[BUFSIZ];
154 	char def[BUFSIZ];
155 	int part = *s - 'a';
156 	struct partition *p = &lp->d_partitions[part];
157 
158 	if (part >= lp->d_npartitions)
159 		lp->d_npartitions = part + 1;
160 
161 	for (;;) {
162 		deffstypename(def, p->p_fstype);
163 		i = getinput(":", "Filesystem type", def, line);
164 		if (i <= 0)
165 			break;
166 		if ((i = getfstypename(line)) == -1) {
167 			printf("Invalid file system typename `%s'\n", line);
168 			continue;
169 		}
170 		p->p_fstype = i;
171 		break;
172 	}
173 	for (;;) {
174 		defnum(def, lp, p->p_offset);
175 		i = getinput(":", "Start offset", def, line);
176 		if (i <= 0)
177 			break;
178 		if ((i = getnum(line, lp)) == -1) {
179 			printf("Bad offset `%s'\n", line);
180 			continue;
181 		}
182 		p->p_offset = i;
183 		break;
184 	}
185 	for (;;) {
186 		defnum(def, lp, p->p_size);
187 		i = getinput(":", "Partition size", def, line);
188 		if (i <= 0)
189 			break;
190 		if ((i = getnum(line, lp)) == -1) {
191 			printf("Bad size `%s'\n", line);
192 			continue;
193 		}
194 		p->p_size = i;
195 		break;
196 	}
197 }
198 
199 
200 static void
201 cmd_label(lp, s, fd)
202 	struct disklabel *lp;
203 	char *s;
204 	int fd;
205 {
206 	char line[BUFSIZ];
207 	int i;
208 
209 	i = getinput("?", "Label disk", "n", line);
210 
211 	if (i <= 0 || *line != 'y')
212 		return;
213 
214 	if (checklabel(lp) != 0) {
215 		printf("Label not written\n");
216 		return;
217 	}
218 
219 	if ((i = writelabel(fd, bootarea, lp)) != 0) {
220 		printf("Label not written %d\n", strerror(i));
221 		return;
222 	}
223 	printf("Label written\n");
224 }
225 
226 
227 static int
228 runcmd(line, lp, fd)
229 	char *line;
230 	struct disklabel *lp;
231 	int fd;
232 {
233 	struct cmds *cmd;
234 
235 	for (cmd = cmds; cmd->name != NULL; cmd++)
236 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
237 			if (cmd->func == NULL)
238 				return -1;
239 			(*cmd->func)(lp, line, fd);
240 			return;
241 		}
242 
243 	if (line[1] == '\0' &&
244 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
245 		cmd_part(lp, line, fd);
246 		return;
247 	}
248 
249 	printf("Unknown command %s\n", line);
250 }
251 
252 
253 static int
254 getinput(sep, prompt, def, line)
255 	const char *sep;
256 	const char *prompt;
257 	const char *def;
258 	char *line;
259 {
260 	for (;;) {
261 		printf("%s", prompt);
262 		if (def)
263 			printf(" [%s]", def);
264 		printf("%s ", sep);
265 
266 		if (fgets(line, BUFSIZ, stdin) == NULL)
267 			return -1;
268 		if (line[0] == '\n' || line[0] == '\0') {
269 			if (def)
270 				return 0;
271 		}
272 		else {
273 			char *p;
274 
275 			if ((p = strrchr(line, '\n')) != NULL)
276 				*p = '\0';
277 			return 1;
278 		}
279 	}
280 }
281 
282 
283 static void
284 defnum(buf, lp, size)
285 	char *buf;
286 	struct disklabel *lp;
287 	int size;
288 {
289 	(void) snprintf(buf, BUFSIZ, "%gc, %ds, %gM",
290 	    size / (float) lp->d_secpercyl,
291 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
292 }
293 
294 
295 static int
296 getnum(buf, lp)
297 	char *buf;
298 	struct disklabel *lp;
299 {
300 	char *ep;
301 	double d = strtod(buf, &ep);
302 	int rv;
303 
304 	if (buf == ep)
305 		return -1;
306 
307 #define ROUND(a)	((a / lp->d_secpercyl) + \
308 			 ((a % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl
309 
310 	switch (*ep) {
311 	case '\0':
312 	case 's':
313 		rv = (int) d;
314 		break;
315 
316 	case 'c':
317 		rv = (int) (d * lp->d_secpercyl);
318 		break;
319 
320 	case 'M':
321 		rv =  (int) (d * 1024 * 1024 / lp->d_secsize);
322 		break;
323 
324 	default:
325 		printf("Unit error %c\n", *ep);
326 		return -1;
327 	}
328 
329 	if (rounding)
330 		return ROUND(rv);
331 	else
332 		return rv;
333 }
334 
335 
336 static void
337 deffstypename(buf, i)
338 	char *buf;
339 	int i;
340 {
341 	if (i < 0 || i >= DKMAXTYPES)
342 		i = 0;
343 	(void) strcpy(buf, fstypenames[i]);
344 }
345 
346 
347 static int
348 getfstypename(buf)
349 	const char *buf;
350 {
351 	int i;
352 
353 	for (i = 0; i < DKMAXTYPES; i++)
354 		if (strcmp(buf, fstypenames[i]) == 0)
355 			return i;
356 	return -1;
357 }
358 
359 
360 void
361 interact(lp, fd)
362 	struct disklabel *lp;
363 	int fd;
364 {
365 	char line[BUFSIZ];
366 
367 	for (;;) {
368 		if (getinput(">", "partition", NULL, line) == -1)
369 			return;
370 		if (runcmd(line, lp, fd) == -1)
371 			return;
372 	}
373 }
374