Home | History | Annotate | Line # | Download | only in disklabel
interact.c revision 1.14
      1 /*	$NetBSD: interact.c,v 1.14 2000/08/14 22:37:08 lukem 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.14 2000/08/14 22:37:08 lukem 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 int alphacmp __P((const void *, const void *));
     62 static void defnum __P((char *, struct disklabel *, int));
     63 static void dumpnames __P((const char *, const char * const *, size_t));
     64 static int getnum __P((char *, int, struct disklabel *));
     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 	if (i <= 0)
    115 		return;
    116 
    117 	switch (line[0]) {
    118 	case 'y':
    119 		chaining = 1;
    120 		return;
    121 	case 'n':
    122 		chaining = 0;
    123 		return;
    124 	default:
    125 		printf("Invalid answer\n");
    126 		return;
    127 	}
    128 }
    129 
    130 static void
    131 cmd_printall(lp, s, fd)
    132 	struct disklabel *lp;
    133 	char *s;
    134 	int fd;
    135 {
    136 
    137 	showinfo(stdout, lp);
    138 	showpartitions(stdout, lp);
    139 }
    140 
    141 static void
    142 cmd_print(lp, s, fd)
    143 	struct disklabel *lp;
    144 	char *s;
    145 	int fd;
    146 {
    147 	showpartitions(stdout, lp);
    148 }
    149 
    150 static void
    151 cmd_info(lp, s, fd)
    152 	struct disklabel *lp;
    153 	char *s;
    154 	int fd;
    155 {
    156 	char line[BUFSIZ];
    157 	char def[BUFSIZ];
    158 	int v, i;
    159 	u_int32_t u;
    160 
    161 	printf("# Current values:\n");
    162 	showinfo(stdout, lp);
    163 
    164 	/* d_type */
    165 	for (;;) {
    166 		i = lp->d_type;
    167 		if (i < 0 || i >= DKMAXTYPES)
    168 			i = 0;
    169 		snprintf(def, sizeof(def), "%s", dktypenames[i]);
    170 		i = getinput(":", "Disk type [?]", def, line);
    171 		if (i == -1)
    172 			return;
    173 		else if (i == 0)
    174 			break;
    175 		if (!strcmp(line, "?")) {
    176 			dumpnames("Supported disk types", dktypenames,
    177 			    DKMAXTYPES);
    178 			continue;
    179 		}
    180 		for (i = 0; i < DKMAXTYPES; i++) {
    181 			if (!strcasecmp(dktypenames[i], line)) {
    182 				lp->d_type = i;
    183 				goto done_typename;
    184 			}
    185 		}
    186 		v = atoi(line);
    187 		if ((unsigned)v >= DKMAXTYPES) {
    188 			warnx("Unknown disk type: %s", line);
    189 			continue;
    190 		}
    191 		lp->d_type = v;
    192 done_typename:
    193 		break;
    194 	}
    195 
    196 	/* d_typename */
    197 	snprintf(def, sizeof(def), "%.*s",
    198 	    (int) sizeof(lp->d_typename), lp->d_typename);
    199 	i = getinput(":", "Disk name", def, line);
    200 	if (i == -1)
    201 		return;
    202 	else if (i == 1)
    203 		(void) strncpy(lp->d_typename, line, sizeof(lp->d_typename));
    204 
    205 	/* d_packname */
    206 	cmd_name(lp, s, fd);
    207 
    208 	/* d_npartitions */
    209 	for (;;) {
    210 		snprintf(def, sizeof(def), "%u", lp->d_npartitions);
    211 		i = getinput(":", "Number of partitions", def, line);
    212 		if (i == -1)
    213 			return;
    214 		else if (i == 0)
    215 			break;
    216 		if (sscanf(line, "%u", &u) != 1) {
    217 			printf("Invalid number of partitions `%s'\n", line);
    218 			continue;
    219 		}
    220 		lp->d_npartitions = u;
    221 		break;
    222 	}
    223 
    224 	/* d_secsize */
    225 	for (;;) {
    226 		snprintf(def, sizeof(def), "%u", lp->d_secsize);
    227 		i = getinput(":", "Sector size (bytes)", def, line);
    228 		if (i == -1)
    229 			return;
    230 		else if (i == 0)
    231 			break;
    232 		if (sscanf(line, "%u", &u) != 1) {
    233 			printf("Invalid sector size `%s'\n", line);
    234 			continue;
    235 		}
    236 		lp->d_secsize = u;
    237 		break;
    238 	}
    239 
    240 	/* d_nsectors */
    241 	for (;;) {
    242 		snprintf(def, sizeof(def), "%u", lp->d_nsectors);
    243 		i = getinput(":", "Number of sectors per track", def, line);
    244 		if (i == -1)
    245 			return;
    246 		else if (i == 0)
    247 			break;
    248 		if (sscanf(line, "%u", &u) != 1) {
    249 			printf("Invalid number of sectors `%s'\n", line);
    250 			continue;
    251 		}
    252 		lp->d_nsectors = u;
    253 		break;
    254 	}
    255 
    256 	/* d_ntracks */
    257 	for (;;) {
    258 		snprintf(def, sizeof(def), "%u", lp->d_ntracks);
    259 		i = getinput(":", "Number of tracks per cylinder", def, line);
    260 		if (i == -1)
    261 			return;
    262 		else if (i == 0)
    263 			break;
    264 		if (sscanf(line, "%u", &u) != 1) {
    265 			printf("Invalid number of tracks `%s'\n", line);
    266 			continue;
    267 		}
    268 		lp->d_ntracks = u;
    269 		break;
    270 	}
    271 
    272 	/* d_secpercyl */
    273 	for (;;) {
    274 		snprintf(def, sizeof(def), "%u", lp->d_secpercyl);
    275 		i = getinput(":", "Number of sectors/cylinder", def, line);
    276 		if (i == -1)
    277 			return;
    278 		else if (i == 0)
    279 			break;
    280 		if (sscanf(line, "%u", &u) != 1) {
    281 			printf("Invalid number of sector/cylinder `%s'\n",
    282 			    line);
    283 			continue;
    284 		}
    285 		lp->d_secpercyl = u;
    286 		break;
    287 	}
    288 
    289 	/* d_ncylinders */
    290 	for (;;) {
    291 		snprintf(def, sizeof(def), "%u", lp->d_ncylinders);
    292 		i = getinput(":", "Total number of cylinders", def, line);
    293 		if (i == -1)
    294 			return;
    295 		else if (i == 0)
    296 			break;
    297 		if (sscanf(line, "%u", &u) != 1) {
    298 			printf("Invalid sector size `%s'\n", line);
    299 			continue;
    300 		}
    301 		lp->d_ncylinders = u;
    302 		break;
    303 	}
    304 
    305 	/* d_secperunit */
    306 	for (;;) {
    307 		snprintf(def, sizeof(def), "%u", lp->d_secperunit);
    308 		i = getinput(":", "Total number of sectors", def, line);
    309 		if (i == -1)
    310 			return;
    311 		else if (i == 0)
    312 			break;
    313 		if (sscanf(line, "%u", &u) != 1) {
    314 			printf("Invalid number of sectors `%s'\n", line);
    315 			continue;
    316 		}
    317 		lp->d_secperunit = u;
    318 		break;
    319 	}
    320 
    321 	/* d_rpm */
    322 
    323 	/* d_interleave */
    324 	for (;;) {
    325 		snprintf(def, sizeof(def), "%u", lp->d_interleave);
    326 		i = getinput(":", "Hardware sectors interleave", def, line);
    327 		if (i == -1)
    328 			return;
    329 		else if (i == 0)
    330 			break;
    331 		if (sscanf(line, "%u", &u) != 1) {
    332 			printf("Invalid sector interleave `%s'\n", line);
    333 			continue;
    334 		}
    335 		lp->d_interleave = u;
    336 		break;
    337 	}
    338 
    339 	/* d_trackskew */
    340 	for (;;) {
    341 		snprintf(def, sizeof(def), "%u", lp->d_trackskew);
    342 		i = getinput(":", "Sector 0 skew, per track", def, line);
    343 		if (i == -1)
    344 			return;
    345 		else if (i == 0)
    346 			break;
    347 		if (sscanf(line, "%u", &u) != 1) {
    348 			printf("Invalid track sector skew `%s'\n", line);
    349 			continue;
    350 		}
    351 		lp->d_trackskew = u;
    352 		break;
    353 	}
    354 
    355 	/* d_cylskew */
    356 	for (;;) {
    357 		snprintf(def, sizeof(def), "%u", lp->d_cylskew);
    358 		i = getinput(":", "Sector 0 skew, per cylinder", def, line);
    359 		if (i == -1)
    360 			return;
    361 		else if (i == 0)
    362 			break;
    363 		if (sscanf(line, "%u", &u) != 1) {
    364 			printf("Invalid cylinder sector `%s'\n", line);
    365 			continue;
    366 		}
    367 		lp->d_cylskew = u;
    368 		break;
    369 	}
    370 
    371 	/* d_headswitch */
    372 	for (;;) {
    373 		snprintf(def, sizeof(def), "%u", lp->d_headswitch);
    374 		i = getinput(":", "Head switch time (usec)", def, line);
    375 		if (i == -1)
    376 			return;
    377 		else if (i == 0)
    378 			break;
    379 		if (sscanf(line, "%u", &u) != 1) {
    380 			printf("Invalid head switch time `%s'\n", line);
    381 			continue;
    382 		}
    383 		lp->d_headswitch = u;
    384 		break;
    385 	}
    386 
    387 	/* d_trkseek */
    388 	for (;;) {
    389 		snprintf(def, sizeof(def), "%u", lp->d_trkseek);
    390 		i = getinput(":", "Track seek time (usec)", def, line);
    391 		if (i == -1)
    392 			return;
    393 		else if (i == 0)
    394 			break;
    395 		if (sscanf(line, "%u", &u) != 1) {
    396 			printf("Invalid track seek time `%s'\n", line);
    397 			continue;
    398 		}
    399 		lp->d_trkseek = u;
    400 		break;
    401 	}
    402 }
    403 
    404 static void
    405 cmd_name(lp, s, fd)
    406 	struct disklabel *lp;
    407 	char *s;
    408 	int fd;
    409 {
    410 	char line[BUFSIZ];
    411 	int i;
    412 
    413 	snprintf(line, sizeof(line), "%.*s",
    414 	    (int) sizeof(lp->d_packname), lp->d_packname);
    415 	i = getinput(":", "Label name", lp->d_packname, line);
    416 	if (i <= 0)
    417 		return;
    418 	(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
    419 }
    420 
    421 static void
    422 cmd_round(lp, s, fd)
    423 	struct disklabel *lp;
    424 	char *s;
    425 	int fd;
    426 {
    427 	int i;
    428 	char line[BUFSIZ];
    429 
    430 	i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
    431 	if (i <= 0)
    432 		return;
    433 
    434 	switch (line[0]) {
    435 	case 'c':
    436 		rounding = 1;
    437 		return;
    438 	case 's':
    439 		rounding = 0;
    440 		return;
    441 	default:
    442 		printf("Rounding can be (c)ylinders or (s)ectors\n");
    443 		return;
    444 	}
    445 }
    446 
    447 static void
    448 cmd_part(lp, s, fd)
    449 	struct disklabel *lp;
    450 	char *s;
    451 	int fd;
    452 {
    453 	int i;
    454 	char line[BUFSIZ];
    455 	char def[BUFSIZ];
    456 	int part = *s - 'a';
    457 	struct partition *p = &lp->d_partitions[part];
    458 
    459 	if (part >= lp->d_npartitions)
    460 		lp->d_npartitions = part + 1;
    461 
    462 	for (;;) {
    463 		i = p->p_fstype;
    464 		if (i < 0 || i >= FSMAXTYPES)
    465 			i = 0;
    466 		snprintf(def, sizeof(def), "%s", fstypenames[i]);
    467 		i = getinput(":", "Filesystem type [?]", def, line);
    468 		if (i == -1)
    469 			return;
    470 		else if (i == 0)
    471 			break;
    472 		if (!strcmp(line, "?")) {
    473 			dumpnames("Supported file system types",
    474 			    fstypenames, FSMAXTYPES);
    475 			continue;
    476 		}
    477 		for (i = 0; i < FSMAXTYPES; i++)
    478 			if (!strcasecmp(line, fstypenames[i])) {
    479 				p->p_fstype = i;
    480 				goto done_typename;
    481 			}
    482 		printf("Invalid file system typename `%s'\n", line);
    483 		continue;
    484 done_typename:
    485 		break;
    486 	}
    487 	for (;;) {
    488 		defnum(def, lp, p->p_offset);
    489 		i = getinput(":", "Start offset", def, line);
    490 		if (i == -1)
    491 			return;
    492 		else if (i == 0)
    493 			break;
    494 		if ((i = getnum(line, 0, lp)) == -1) {
    495 			printf("Bad offset `%s'\n", line);
    496 			continue;
    497 		}
    498 		p->p_offset = i;
    499 		break;
    500 	}
    501 	for (;;) {
    502 		defnum(def, lp, p->p_size);
    503 		i = getinput(":", "Partition size ('$' for all remaining)",
    504 		    def, line);
    505 		if (i == -1)
    506 			return;
    507 		else if (i == 0)
    508 			break;
    509 		if ((i = getnum(line, lp->d_secperunit - p->p_offset, lp))
    510 		    == -1) {
    511 			printf("Bad size `%s'\n", line);
    512 			continue;
    513 		}
    514 		p->p_size = i;
    515 		break;
    516 	}
    517 
    518 	if (chaining) {
    519 		int offs = p[0].p_offset + p[0].p_size;
    520 		p = lp->d_partitions;
    521 		part = getrawpartition();
    522 		for (i = 1; i < lp->d_npartitions; i++) {
    523 			if (i != part && p[i].p_fstype) {
    524 				p[i].p_offset = offs;
    525 				offs = p[i].p_offset + p[i].p_size;
    526 			}
    527 		}
    528 	}
    529 }
    530 
    531 
    532 static void
    533 cmd_label(lp, s, fd)
    534 	struct disklabel *lp;
    535 	char *s;
    536 	int fd;
    537 {
    538 	char line[BUFSIZ];
    539 	int i;
    540 
    541 	i = getinput("?", "Label disk", "n", line);
    542 	if (i <= 0 || (*line != 'y' && *line != 'Y') )
    543 		return;
    544 
    545 	if (checklabel(lp) != 0) {
    546 		printf("Label not written\n");
    547 		return;
    548 	}
    549 
    550 	if (writelabel(fd, bootarea, lp) != 0) {
    551 		printf("Label not written\n");
    552 		return;
    553 	}
    554 	printf("Label written\n");
    555 }
    556 
    557 
    558 static int
    559 runcmd(line, lp, fd)
    560 	char *line;
    561 	struct disklabel *lp;
    562 	int fd;
    563 {
    564 	struct cmds *cmd;
    565 
    566 	for (cmd = cmds; cmd->name != NULL; cmd++)
    567 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
    568 			if (cmd->func == NULL)
    569 				return -1;
    570 			(*cmd->func)(lp, line, fd);
    571 			return 0;
    572 		}
    573 
    574 	if (line[1] == '\0' &&
    575 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
    576 		cmd_part(lp, line, fd);
    577 		return 0;
    578 	}
    579 
    580 	printf("Unknown command %s\n", line);
    581 	return 1;
    582 }
    583 
    584 
    585 static int
    586 getinput(sep, prompt, def, line)
    587 	const char *sep;
    588 	const char *prompt;
    589 	const char *def;
    590 	char *line;
    591 {
    592 	for (;;) {
    593 		printf("%s", prompt);
    594 		if (def)
    595 			printf(" [%s]", def);
    596 		printf("%s ", sep);
    597 
    598 		if (fgets(line, BUFSIZ, stdin) == NULL)
    599 			return -1;
    600 		if (line[0] == '\n' || line[0] == '\0') {
    601 			if (def)
    602 				return 0;
    603 		}
    604 		else {
    605 			char *p;
    606 
    607 			if ((p = strrchr(line, '\n')) != NULL)
    608 				*p = '\0';
    609 			return 1;
    610 		}
    611 	}
    612 }
    613 
    614 static int
    615 alphacmp(a, b)
    616 	const void *a, *b;
    617 {
    618 
    619 	return (strcasecmp(*(const char **)a, *(const char **)b));
    620 }
    621 
    622 
    623 static void
    624 dumpnames(prompt, olist, numentries)
    625 	const char *prompt;
    626 	const char * const *olist;
    627 	size_t numentries;
    628 {
    629 	int i, j, w;
    630 	int columns, width, lines;
    631 	const char *p;
    632 	const char **list;
    633 
    634 	list = (const char **)malloc(sizeof(char *) * numentries);
    635 	width = 0;
    636 	printf("%s:\n", prompt);
    637 	for (i = 0; i < numentries; i++) {
    638 		list[i] = olist[i];
    639 		w = strlen(list[i]);
    640 		if (w > width)
    641 			width = w;
    642 	}
    643 #if 0
    644 	for (i = 0; i < numentries; i++)
    645 		printf("%s%s", i == 0 ? "" : ", ", list[i]);
    646 	puts("");
    647 #endif
    648 	(void)qsort((void *)list, numentries, sizeof(char *), alphacmp);
    649 	width++;		/* want two spaces between items */
    650 	width = (width + 8) &~ 7;
    651 
    652 #define ttywidth 72
    653 	columns = ttywidth / width;
    654 #undef ttywidth
    655 	if (columns == 0)
    656 		columns = 1;
    657 	lines = (numentries + columns - 1) / columns;
    658 	for (i = 0; i < lines; i++) {
    659 		for (j = 0; j < columns; j++) {
    660 			p = list[j * lines + i];
    661 			if (j == 0)
    662 				putc('\t', stdout);
    663 			if (p) {
    664 				fputs(p, stdout);
    665 			}
    666 			if (j * lines + i + lines >= numentries) {
    667 				putc('\n', stdout);
    668 				break;
    669 			}
    670 			w = strlen(p);
    671 			while (w < width) {
    672 				w = (w + 8) &~ 7;
    673 				putc('\t', stdout);
    674 			}
    675 		}
    676 	}
    677 	free(list);
    678 }
    679 
    680 
    681 static void
    682 defnum(buf, lp, size)
    683 	char *buf;
    684 	struct disklabel *lp;
    685 	int size;
    686 {
    687 	(void) snprintf(buf, BUFSIZ, "%gc, %ds, %gM",
    688 	    size / (float) lp->d_secpercyl,
    689 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
    690 }
    691 
    692 
    693 static int
    694 getnum(buf, max, lp)
    695 	char *buf;
    696 	int max;
    697 	struct disklabel *lp;
    698 {
    699 	char *ep;
    700 	double d;
    701 	int rv;
    702 
    703 	if (max && buf[0] == '$' && buf[1] == 0)
    704 		return max;
    705 
    706 	d = strtod(buf, &ep);
    707 	if (buf == ep)
    708 		return -1;
    709 
    710 #define ROUND(a)	((a / lp->d_secpercyl) + \
    711 		 ((a % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl
    712 
    713 	switch (*ep) {
    714 	case '\0':
    715 	case 's':
    716 		rv = (int) d;
    717 		break;
    718 
    719 	case 'c':
    720 		rv = (int) (d * lp->d_secpercyl);
    721 		break;
    722 
    723 	case 'm':
    724 	case 'M':
    725 		rv =  (int) (d * 1024 * 1024 / lp->d_secsize);
    726 		break;
    727 
    728 	default:
    729 		printf("Unit error %c\n", *ep);
    730 		return -1;
    731 	}
    732 
    733 	if (rounding)
    734 		return ROUND(rv);
    735 	else
    736 		return rv;
    737 }
    738 
    739 
    740 void
    741 interact(lp, fd)
    742 	struct disklabel *lp;
    743 	int fd;
    744 {
    745 	char line[BUFSIZ];
    746 
    747 	for (;;) {
    748 		if (getinput(">", "partition", NULL, line) == -1)
    749 			return;
    750 		if (runcmd(line, lp, fd) == -1)
    751 			return;
    752 	}
    753 }
    754