xref: /netbsd-src/sbin/disklabel/interact.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: interact.c,v 1.13 1999/12/17 13:06:49 abs 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 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: interact.c,v 1.13 1999/12/17 13:06:49 abs Exp $");
35 #endif /* lint */
36 
37 #include <sys/param.h>
38 #define FSTYPENAMES
39 #define DKTYPENAMES
40 #include <sys/disklabel.h>
41 
42 #include <err.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <util.h>
47 
48 #include "extern.h"
49 
50 static void cmd_help __P((struct disklabel *, char *, int));
51 static void cmd_chain __P((struct disklabel *, char *, int));
52 static void cmd_print __P((struct disklabel *, char *, int));
53 static void cmd_printall __P((struct disklabel *, char *, int));
54 static void cmd_info __P((struct disklabel *, char *, int));
55 static void cmd_part __P((struct disklabel *, char *, int));
56 static void cmd_label __P((struct disklabel *, char *, int));
57 static void cmd_round __P((struct disklabel *, char *, int));
58 static void cmd_name __P((struct disklabel *, char *, int));
59 static int runcmd __P((char *, struct disklabel *, int));
60 static int getinput __P((const char *, const char *, const char *, char *));
61 static void defnum __P((char *, struct disklabel *, int));
62 static int getnum __P((char *, int, struct disklabel *));
63 static void deffstypename __P((char *, int));
64 static int getfstypename __P((const char *));
65 
66 static int rounding = 0;	/* sector rounding */
67 static int chaining = 0;	/* make partitions contiguous */
68 
69 static struct cmds {
70 	const char *name;
71 	void (*func) __P((struct disklabel *, char *, int));
72 	const char *help;
73 } cmds[] = {
74 	{ "?",	cmd_help,	"print this menu" },
75 	{ "C",	cmd_chain,	"make partitions contiguous" },
76 	{ "E",	cmd_printall,	"print disk label and current partition table"},
77 	{ "I",	cmd_info,	"change label information" },
78 	{ "N",	cmd_name,	"name the label" },
79 	{ "P",	cmd_print,	"print current partition table" },
80 	{ "Q",	NULL,		"quit" },
81 	{ "R",	cmd_round,	"rounding (c)ylinders (s)ectors" },
82 	{ "W",	cmd_label,	"write the current partition table" },
83 	{ NULL, NULL,		NULL }
84 };
85 
86 
87 
88 static void
89 cmd_help(lp, s, fd)
90 	struct disklabel *lp;
91 	char *s;
92 	int fd;
93 {
94 	struct cmds *cmd;
95 
96 	for (cmd = cmds; cmd->name != NULL; cmd++)
97 		printf("%s\t%s\n", cmd->name, cmd->help);
98 	printf("[a-%c]\tdefine named partition\n",
99 	    'a' + getmaxpartitions() - 1);
100 }
101 
102 
103 static void
104 cmd_chain(lp, s, fd)
105 	struct disklabel *lp;
106 	char *s;
107 	int fd;
108 {
109 	int i;
110 	char line[BUFSIZ];
111 
112 	i = getinput(":", "Automatically adjust partitions",
113 	    chaining ? "yes" : "no", line);
114 
115 	if (i <= 0)
116 		return;
117 
118 	switch (line[0]) {
119 	case 'y':
120 		chaining = 1;
121 		return;
122 	case 'n':
123 		chaining = 0;
124 		return;
125 	default:
126 		printf("Invalid answer\n");
127 		return;
128 	}
129 }
130 
131 static void
132 cmd_printall(lp, s, fd)
133 	struct disklabel *lp;
134 	char *s;
135 	int fd;
136 {
137 
138 	showinfo(stdout, lp);
139 	showpartitions(stdout, lp);
140 }
141 
142 static void
143 cmd_print(lp, s, fd)
144 	struct disklabel *lp;
145 	char *s;
146 	int fd;
147 {
148 	showpartitions(stdout, lp);
149 }
150 
151 static void
152 cmd_info(lp, s, fd)
153 	struct disklabel *lp;
154 	char *s;
155 	int fd;
156 {
157 	char line[BUFSIZ];
158 	char def[BUFSIZ];
159 	const char * const *cpp;
160 	const char *t;
161 	int v, i;
162 	u_int32_t u;
163 
164 	printf("# Current values:\n");
165 	showinfo(stdout, lp);
166 
167 	/* d_typename */
168 	for (;;) {
169 		strncpy(def, lp->d_typename, sizeof(def));
170 		def[sizeof(def) - 1] = '\0';
171 		i = getinput(":", "Disk type", def, line);
172 		if (i <= 0)
173 			break;
174 		cpp = dktypenames;
175 		for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
176 			if ((t = *cpp) && !strcmp(t, line)) {
177 				lp->d_type = cpp - dktypenames;
178 				goto done_typename;
179 			}
180 		v = atoi(line);
181 		if ((unsigned)v >= DKMAXTYPES) {
182 			warnx("unknown disk type: %s", line);
183 			continue;
184 		}
185 		lp->d_type = v;
186 done_typename:
187 		break;
188 	}
189 
190 	/* d_packname */
191 	cmd_name(lp, s, fd);
192 
193 	/* d_npartitions */
194 	for (;;) {
195 		snprintf(def, sizeof def, "%u", lp->d_npartitions);
196 		i = getinput(":", "Number of partitions", def, line);
197 		if (i <= 0)
198 			break;
199 		if (sscanf(line, "%u", &u) != 1) {
200 			printf("Invalid sector size `%s'\n", line);
201 			continue;
202 		}
203 		lp->d_npartitions = u;
204 		break;
205 	}
206 
207 	/* d_secsize */
208 	for (;;) {
209 		snprintf(def, sizeof def, "%u", lp->d_secsize);
210 		i = getinput(":", "Sector size (bytes)", def, line);
211 		if (i <= 0)
212 			break;
213 		if (sscanf(line, "%u", &u) != 1) {
214 			printf("Invalid sector size `%s'\n", line);
215 			continue;
216 		}
217 		lp->d_secsize = u;
218 		break;
219 	}
220 
221 	/* d_nsectors */
222 	for (;;) {
223 		snprintf(def, sizeof def, "%u", lp->d_nsectors);
224 		i = getinput(":", "Number of sectors per track", def, line);
225 		if (i <= 0)
226 			break;
227 		if (sscanf(line, "%u", &u) != 1) {
228 			printf("Invalid number of sector `%s'\n", line);
229 			continue;
230 		}
231 		lp->d_nsectors = u;
232 		break;
233 	}
234 
235 	/* d_ntracks */
236 	for (;;) {
237 		snprintf(def, sizeof def, "%u", lp->d_ntracks);
238 		i = getinput(":", "Number of tracks per cylinder", def, line);
239 		if (i <= 0)
240 			break;
241 		if (sscanf(line, "%u", &u) != 1) {
242 			printf("Invalid number of tracks `%s'\n", line);
243 			continue;
244 		}
245 		lp->d_ntracks = u;
246 		break;
247 	}
248 
249 	/* d_secpercyl */
250 	for (;;) {
251 		snprintf(def, sizeof def, "%u", lp->d_secpercyl);
252 		i = getinput(":", "Number of sectors/cylinder", def, line);
253 		if (i <= 0)
254 			break;
255 		if (sscanf(line, "%u", &u) != 1) {
256 			printf("Invalid number of sector/cylinder `%s'\n", line);
257 			continue;
258 		}
259 		lp->d_secpercyl = u;
260 		break;
261 	}
262 
263 	/* d_ncylinders */
264 	for (;;) {
265 		snprintf(def, sizeof def, "%u", lp->d_ncylinders);
266 		i = getinput(":", "Total number of cylinders", def, line);
267 		if (i <= 0)
268 			break;
269 		if (sscanf(line, "%u", &u) != 1) {
270 			printf("Invalid sector size `%s'\n", line);
271 			continue;
272 		}
273 		lp->d_ncylinders = u;
274 		break;
275 	}
276 
277 	/* d_secperunit */
278 	for (;;) {
279 		snprintf(def, sizeof def, "%u", lp->d_secperunit);
280 		i = getinput(":", "Total number of sectors", def, line);
281 		if (i <= 0)
282 			break;
283 		if (sscanf(line, "%u", &u) != 1) {
284 			printf("Invalid number of sector `%s'\n", line);
285 			continue;
286 		}
287 		lp->d_secperunit = u;
288 		break;
289 	}
290 
291 	/* d_rpm */
292 
293 	/* d_interleave */
294 	for (;;) {
295 		snprintf(def, sizeof def, "%u", lp->d_interleave);
296 		i = getinput(":", "Hardware sectors interleave", def, line);
297 
298 		if (i <= 0)
299 			break;
300 		if (sscanf(line, "%u", &u) != 1) {
301 			printf("Invalid sector size `%s'\n", line);
302 			continue;
303 		}
304 		lp->d_interleave = u;
305 		break;
306 	}
307 
308 	/* d_trackskew */
309 	for (;;) {
310 		snprintf(def, sizeof def, "%u", lp->d_trackskew);
311 		i = getinput(":", "Sector 0 skew, per track", def, line);
312 		if (i <= 0)
313 			break;
314 		if (sscanf(line, "%u", &u) != 1) {
315 			printf("Invalid sector size `%s'\n", line);
316 			continue;
317 		}
318 		lp->d_trackskew = u;
319 		break;
320 	}
321 
322 	/* d_cylskew */
323 	for (;;) {
324 		snprintf(def, sizeof def, "%u", lp->d_cylskew);
325 		i = getinput(":", "Sector 0 skew, per cylinder", def, line);
326 		if (i <= 0)
327 			break;
328 		if (sscanf(line, "%u", &u) != 1) {
329 			printf("Invalid sector size `%s'\n", line);
330 			continue;
331 		}
332 		lp->d_cylskew = u;
333 		break;
334 	}
335 
336 	/* d_headswitch */
337 	for (;;) {
338 		snprintf(def, sizeof def, "%u", lp->d_headswitch);
339 		i = getinput(":", "Head switch time (usec)", def, line);
340 		if (i <= 0)
341 			break;
342 		if (sscanf(line, "%u", &u) != 1) {
343 			printf("Invalid sector size `%s'\n", line);
344 			continue;
345 		}
346 		lp->d_headswitch = u;
347 		break;
348 	}
349 
350 	/* d_trkseek */
351 	for (;;) {
352 		snprintf(def, sizeof def, "%u", lp->d_trkseek);
353 		i = getinput(":", "Track seek time (usec)", def, line);
354 		if (i <= 0)
355 			break;
356 		if (sscanf(line, "%u", &u) != 1) {
357 			printf("Invalid sector size `%s'\n", line);
358 			continue;
359 		}
360 		lp->d_trkseek = u;
361 		break;
362 	}
363 
364 }
365 
366 static void
367 cmd_name(lp, s, fd)
368 	struct disklabel *lp;
369 	char *s;
370 	int fd;
371 {
372 	char line[BUFSIZ];
373 	int i = getinput(":", "Label name", lp->d_packname, line);
374 
375 	if (i <= 0)
376 		return;
377 	(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
378 }
379 
380 static void
381 cmd_round(lp, s, fd)
382 	struct disklabel *lp;
383 	char *s;
384 	int fd;
385 {
386 	int i;
387 	char line[BUFSIZ];
388 
389 	i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
390 
391 	if (i <= 0)
392 		return;
393 
394 	switch (line[0]) {
395 	case 'c':
396 		rounding = 1;
397 		return;
398 	case 's':
399 		rounding = 0;
400 		return;
401 	default:
402 		printf("Rounding can be (c)ylinders or (s)ectors\n");
403 		return;
404 	}
405 }
406 
407 static void
408 cmd_part(lp, s, fd)
409 	struct disklabel *lp;
410 	char *s;
411 	int fd;
412 {
413 	int i;
414 	char line[BUFSIZ];
415 	char def[BUFSIZ];
416 	int part = *s - 'a';
417 	struct partition *p = &lp->d_partitions[part];
418 
419 	if (part >= lp->d_npartitions)
420 		lp->d_npartitions = part + 1;
421 
422 	for (;;) {
423 		deffstypename(def, p->p_fstype);
424 		i = getinput(":", "Filesystem type", def, line);
425 		if (i <= 0)
426 			break;
427 		if ((i = getfstypename(line)) == -1) {
428 			printf("Invalid file system typename `%s'\n", line);
429 			continue;
430 		}
431 		p->p_fstype = i;
432 		break;
433 	}
434 	for (;;) {
435 		defnum(def, lp, p->p_offset);
436 		i = getinput(":", "Start offset", def, line);
437 		if (i <= 0)
438 			break;
439 		if ((i = getnum(line, 0, lp)) == -1) {
440 			printf("Bad offset `%s'\n", line);
441 			continue;
442 		}
443 		p->p_offset = i;
444 		break;
445 	}
446 	for (;;) {
447 		defnum(def, lp, p->p_size);
448 		i = getinput(":", "Partition size ('$' for all remaining)",
449 		    def, line);
450 		if (i <= 0)
451 			break;
452 		if ((i = getnum(line, lp->d_secperunit - p->p_offset, lp))
453 		    == -1) {
454 			printf("Bad size `%s'\n", line);
455 			continue;
456 		}
457 		p->p_size = i;
458 		break;
459 	}
460 
461 	if (chaining) {
462 		int offs = p[0].p_offset + p[0].p_size;
463 		p = lp->d_partitions;
464 		part = getrawpartition();
465 		for (i = 1; i < lp->d_npartitions; i++) {
466 			if (i != part && p[i].p_fstype) {
467 				p[i].p_offset = offs;
468 				offs = p[i].p_offset + p[i].p_size;
469 			}
470 		}
471 	}
472 }
473 
474 
475 static void
476 cmd_label(lp, s, fd)
477 	struct disklabel *lp;
478 	char *s;
479 	int fd;
480 {
481 	char line[BUFSIZ];
482 	int i;
483 
484 	i = getinput("?", "Label disk", "n", line);
485 
486 	if (i <= 0 || (*line != 'y' && *line != 'Y') )
487 		return;
488 
489 	if (checklabel(lp) != 0) {
490 		printf("Label not written\n");
491 		return;
492 	}
493 
494 	if (writelabel(fd, bootarea, lp) != 0) {
495 		printf("Label not written\n");
496 		return;
497 	}
498 	printf("Label written\n");
499 }
500 
501 
502 static int
503 runcmd(line, lp, fd)
504 	char *line;
505 	struct disklabel *lp;
506 	int fd;
507 {
508 	struct cmds *cmd;
509 
510 	for (cmd = cmds; cmd->name != NULL; cmd++)
511 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
512 			if (cmd->func == NULL)
513 				return -1;
514 			(*cmd->func)(lp, line, fd);
515 			return 0;
516 		}
517 
518 	if (line[1] == '\0' &&
519 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
520 		cmd_part(lp, line, fd);
521 		return 0;
522 	}
523 
524 	printf("Unknown command %s\n", line);
525 	return 1;
526 }
527 
528 
529 static int
530 getinput(sep, prompt, def, line)
531 	const char *sep;
532 	const char *prompt;
533 	const char *def;
534 	char *line;
535 {
536 	for (;;) {
537 		printf("%s", prompt);
538 		if (def)
539 			printf(" [%s]", def);
540 		printf("%s ", sep);
541 
542 		if (fgets(line, BUFSIZ, stdin) == NULL)
543 			return -1;
544 		if (line[0] == '\n' || line[0] == '\0') {
545 			if (def)
546 				return 0;
547 		}
548 		else {
549 			char *p;
550 
551 			if ((p = strrchr(line, '\n')) != NULL)
552 				*p = '\0';
553 			return 1;
554 		}
555 	}
556 }
557 
558 
559 static void
560 defnum(buf, lp, size)
561 	char *buf;
562 	struct disklabel *lp;
563 	int size;
564 {
565 	(void) snprintf(buf, BUFSIZ, "%gc, %ds, %gM",
566 	    size / (float) lp->d_secpercyl,
567 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
568 }
569 
570 
571 static int
572 getnum(buf, max, lp)
573 	char *buf;
574 	int max;
575 	struct disklabel *lp;
576 {
577 	char *ep;
578 	double d;
579 	int rv;
580 
581 	if (max && buf[0] == '$' && buf[1] == 0)
582 		return max;
583 
584 	d = strtod(buf, &ep);
585 	if (buf == ep)
586 		return -1;
587 
588 #define ROUND(a)	((a / lp->d_secpercyl) + \
589 		 ((a % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl
590 
591 	switch (*ep) {
592 	case '\0':
593 	case 's':
594 		rv = (int) d;
595 		break;
596 
597 	case 'c':
598 		rv = (int) (d * lp->d_secpercyl);
599 		break;
600 
601 	case 'M':
602 		rv =  (int) (d * 1024 * 1024 / lp->d_secsize);
603 		break;
604 
605 	default:
606 		printf("Unit error %c\n", *ep);
607 		return -1;
608 	}
609 
610 	if (rounding)
611 		return ROUND(rv);
612 	else
613 		return rv;
614 }
615 
616 
617 static void
618 deffstypename(buf, i)
619 	char *buf;
620 	int i;
621 {
622 	if (i < 0 || i >= FSMAXTYPES)
623 		i = 0;
624 	(void) strcpy(buf, fstypenames[i]);
625 }
626 
627 
628 static int
629 getfstypename(buf)
630 	const char *buf;
631 {
632 	int i;
633 
634 	for (i = 0; i < FSMAXTYPES; i++)
635 		if (strcmp(buf, fstypenames[i]) == 0)
636 			return i;
637 	return -1;
638 }
639 
640 
641 void
642 interact(lp, fd)
643 	struct disklabel *lp;
644 	int fd;
645 {
646 	char line[BUFSIZ];
647 
648 	for (;;) {
649 		if (getinput(">", "partition", NULL, line) == -1)
650 			return;
651 		if (runcmd(line, lp, fd) == -1)
652 			return;
653 	}
654 }
655