Home | History | Annotate | Line # | Download | only in disklabel
interact.c revision 1.28
      1 /*	$NetBSD: interact.c,v 1.28 2006/03/17 14:50:44 rumble 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 #if HAVE_NBTOOL_CONFIG_H
     33 #include "nbtool_config.h"
     34 #endif
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __RCSID("$NetBSD: interact.c,v 1.28 2006/03/17 14:50:44 rumble Exp $");
     39 #endif /* lint */
     40 
     41 #include <sys/param.h>
     42 #define FSTYPENAMES
     43 #define DKTYPENAMES
     44 
     45 #include <err.h>
     46 #include <stdio.h>
     47 #include <string.h>
     48 #include <stdlib.h>
     49 
     50 #if HAVE_NBTOOL_CONFIG_H
     51 #define	getmaxpartitions()	MAXPARTITIONS
     52 #include <nbinclude/sys/disklabel.h>
     53 #else
     54 #include <util.h>
     55 #include <sys/disklabel.h>
     56 #endif /* HAVE_NBTOOL_CONFIG_H */
     57 
     58 #include "extern.h"
     59 
     60 static void	cmd_help(struct disklabel *, char *, int);
     61 static void	cmd_chain(struct disklabel *, char *, int);
     62 static void	cmd_print(struct disklabel *, char *, int);
     63 static void	cmd_printall(struct disklabel *, char *, int);
     64 static void	cmd_info(struct disklabel *, char *, int);
     65 static void	cmd_part(struct disklabel *, char *, int);
     66 static void	cmd_label(struct disklabel *, char *, int);
     67 static void	cmd_round(struct disklabel *, char *, int);
     68 static void	cmd_name(struct disklabel *, char *, int);
     69 static int	runcmd(struct disklabel *, char *, int);
     70 static int	getinput(const char *, const char *, const char *, char *);
     71 static int	alphacmp(const void *, const void *);
     72 static void	defnum(struct disklabel *, char *, uint32_t);
     73 static void	dumpnames(const char *, const char * const *, size_t);
     74 static int	getnum(struct disklabel *, char *, int);
     75 
     76 static int rounding = 0;	/* sector rounding */
     77 static int chaining = 0;	/* make partitions contiguous */
     78 
     79 static struct cmds {
     80 	const char *name;
     81 	void (*func)(struct disklabel *, char *, int);
     82 	const char *help;
     83 } cmds[] = {
     84 	{ "?",	cmd_help,	"print this menu" },
     85 	{ "C",	cmd_chain,	"make partitions contiguous" },
     86 	{ "E",	cmd_printall,	"print disk label and current partition table"},
     87 	{ "I",	cmd_info,	"change label information" },
     88 	{ "N",	cmd_name,	"name the label" },
     89 	{ "P",	cmd_print,	"print current partition table" },
     90 	{ "Q",	NULL,		"quit" },
     91 	{ "R",	cmd_round,	"rounding (c)ylinders (s)ectors" },
     92 	{ "W",	cmd_label,	"write the current partition table" },
     93 	{ NULL, NULL,		NULL }
     94 };
     95 
     96 
     97 
     98 static void
     99 cmd_help(struct disklabel *lp, char *s, int fd)
    100 {
    101 	struct cmds *cmd;
    102 
    103 	for (cmd = cmds; cmd->name != NULL; cmd++)
    104 		printf("%s\t%s\n", cmd->name, cmd->help);
    105 	printf("[a-%c]\tdefine named partition\n",
    106 	    'a' + getmaxpartitions() - 1);
    107 }
    108 
    109 
    110 static void
    111 cmd_chain(struct disklabel *lp, char *s, int fd)
    112 {
    113 	int	i;
    114 	char	line[BUFSIZ];
    115 
    116 	i = getinput(":", "Automatically adjust partitions",
    117 	    chaining ? "yes" : "no", line);
    118 	if (i <= 0)
    119 		return;
    120 
    121 	switch (line[0]) {
    122 	case 'y':
    123 		chaining = 1;
    124 		return;
    125 	case 'n':
    126 		chaining = 0;
    127 		return;
    128 	default:
    129 		printf("Invalid answer\n");
    130 		return;
    131 	}
    132 }
    133 
    134 
    135 static void
    136 cmd_printall(struct disklabel *lp, char *s, int fd)
    137 {
    138 
    139 	showinfo(stdout, lp, specname);
    140 	showpartitions(stdout, lp, Cflag);
    141 }
    142 
    143 
    144 static void
    145 cmd_print(struct disklabel *lp, char *s, int fd)
    146 {
    147 
    148 	showpartitions(stdout, lp, Cflag);
    149 }
    150 
    151 
    152 static void
    153 cmd_info(struct disklabel *lp, char *s, int fd)
    154 {
    155 	char	line[BUFSIZ];
    156 	char	def[BUFSIZ];
    157 	int	v, i;
    158 	u_int32_t u;
    159 
    160 	printf("# Current values:\n");
    161 	showinfo(stdout, lp, specname);
    162 
    163 	/* d_type */
    164 	for (;;) {
    165 		i = lp->d_type;
    166 		if (i < 0 || i >= DKMAXTYPES)
    167 			i = 0;
    168 		snprintf(def, sizeof(def), "%s", dktypenames[i]);
    169 		i = getinput(":", "Disk type [?]", def, line);
    170 		if (i == -1)
    171 			return;
    172 		else if (i == 0)
    173 			break;
    174 		if (!strcmp(line, "?")) {
    175 			dumpnames("Supported disk types", dktypenames,
    176 			    DKMAXTYPES);
    177 			continue;
    178 		}
    179 		for (i = 0; i < DKMAXTYPES; i++) {
    180 			if (!strcasecmp(dktypenames[i], line)) {
    181 				lp->d_type = i;
    182 				goto done_typename;
    183 			}
    184 		}
    185 		v = atoi(line);
    186 		if ((unsigned)v >= DKMAXTYPES) {
    187 			warnx("Unknown disk type: %s", line);
    188 			continue;
    189 		}
    190 		lp->d_type = v;
    191  done_typename:
    192 		break;
    193 	}
    194 
    195 	/* d_typename */
    196 	snprintf(def, sizeof(def), "%.*s",
    197 	    (int) sizeof(lp->d_typename), lp->d_typename);
    198 	i = getinput(":", "Disk name", def, line);
    199 	if (i == -1)
    200 		return;
    201 	else if (i == 1)
    202 		(void) strncpy(lp->d_typename, line, sizeof(lp->d_typename));
    203 
    204 	/* d_packname */
    205 	cmd_name(lp, s, fd);
    206 
    207 	/* d_npartitions */
    208 	for (;;) {
    209 		snprintf(def, sizeof(def), "%u", lp->d_npartitions);
    210 		i = getinput(":", "Number of partitions", def, line);
    211 		if (i == -1)
    212 			return;
    213 		else if (i == 0)
    214 			break;
    215 		if (sscanf(line, "%u", &u) != 1) {
    216 			printf("Invalid number of partitions `%s'\n", line);
    217 			continue;
    218 		}
    219 		lp->d_npartitions = u;
    220 		break;
    221 	}
    222 
    223 	/* d_secsize */
    224 	for (;;) {
    225 		snprintf(def, sizeof(def), "%u", lp->d_secsize);
    226 		i = getinput(":", "Sector size (bytes)", def, line);
    227 		if (i == -1)
    228 			return;
    229 		else if (i == 0)
    230 			break;
    231 		if (sscanf(line, "%u", &u) != 1) {
    232 			printf("Invalid sector size `%s'\n", line);
    233 			continue;
    234 		}
    235 		lp->d_secsize = u;
    236 		break;
    237 	}
    238 
    239 	/* d_nsectors */
    240 	for (;;) {
    241 		snprintf(def, sizeof(def), "%u", lp->d_nsectors);
    242 		i = getinput(":", "Number of sectors per track", def, line);
    243 		if (i == -1)
    244 			return;
    245 		else if (i == 0)
    246 			break;
    247 		if (sscanf(line, "%u", &u) != 1) {
    248 			printf("Invalid number of sectors `%s'\n", line);
    249 			continue;
    250 		}
    251 		lp->d_nsectors = u;
    252 		break;
    253 	}
    254 
    255 	/* d_ntracks */
    256 	for (;;) {
    257 		snprintf(def, sizeof(def), "%u", lp->d_ntracks);
    258 		i = getinput(":", "Number of tracks per cylinder", def, line);
    259 		if (i == -1)
    260 			return;
    261 		else if (i == 0)
    262 			break;
    263 		if (sscanf(line, "%u", &u) != 1) {
    264 			printf("Invalid number of tracks `%s'\n", line);
    265 			continue;
    266 		}
    267 		lp->d_ntracks = u;
    268 		break;
    269 	}
    270 
    271 	/* d_secpercyl */
    272 	for (;;) {
    273 		snprintf(def, sizeof(def), "%u", lp->d_secpercyl);
    274 		i = getinput(":", "Number of sectors/cylinder", def, line);
    275 		if (i == -1)
    276 			return;
    277 		else if (i == 0)
    278 			break;
    279 		if (sscanf(line, "%u", &u) != 1) {
    280 			printf("Invalid number of sector/cylinder `%s'\n",
    281 			    line);
    282 			continue;
    283 		}
    284 		lp->d_secpercyl = u;
    285 		break;
    286 	}
    287 
    288 	/* d_ncylinders */
    289 	for (;;) {
    290 		snprintf(def, sizeof(def), "%u", lp->d_ncylinders);
    291 		i = getinput(":", "Total number of cylinders", def, line);
    292 		if (i == -1)
    293 			return;
    294 		else if (i == 0)
    295 			break;
    296 		if (sscanf(line, "%u", &u) != 1) {
    297 			printf("Invalid sector size `%s'\n", line);
    298 			continue;
    299 		}
    300 		lp->d_ncylinders = u;
    301 		break;
    302 	}
    303 
    304 	/* d_secperunit */
    305 	for (;;) {
    306 		snprintf(def, sizeof(def), "%u", lp->d_secperunit);
    307 		i = getinput(":", "Total number of sectors", def, line);
    308 		if (i == -1)
    309 			return;
    310 		else if (i == 0)
    311 			break;
    312 		if (sscanf(line, "%u", &u) != 1) {
    313 			printf("Invalid number of sectors `%s'\n", line);
    314 			continue;
    315 		}
    316 		lp->d_secperunit = u;
    317 		break;
    318 	}
    319 
    320 	/* d_rpm */
    321 
    322 	/* d_interleave */
    323 	for (;;) {
    324 		snprintf(def, sizeof(def), "%u", lp->d_interleave);
    325 		i = getinput(":", "Hardware sectors interleave", def, line);
    326 		if (i == -1)
    327 			return;
    328 		else if (i == 0)
    329 			break;
    330 		if (sscanf(line, "%u", &u) != 1) {
    331 			printf("Invalid sector interleave `%s'\n", line);
    332 			continue;
    333 		}
    334 		lp->d_interleave = u;
    335 		break;
    336 	}
    337 
    338 	/* d_trackskew */
    339 	for (;;) {
    340 		snprintf(def, sizeof(def), "%u", lp->d_trackskew);
    341 		i = getinput(":", "Sector 0 skew, per track", def, line);
    342 		if (i == -1)
    343 			return;
    344 		else if (i == 0)
    345 			break;
    346 		if (sscanf(line, "%u", &u) != 1) {
    347 			printf("Invalid track sector skew `%s'\n", line);
    348 			continue;
    349 		}
    350 		lp->d_trackskew = u;
    351 		break;
    352 	}
    353 
    354 	/* d_cylskew */
    355 	for (;;) {
    356 		snprintf(def, sizeof(def), "%u", lp->d_cylskew);
    357 		i = getinput(":", "Sector 0 skew, per cylinder", def, line);
    358 		if (i == -1)
    359 			return;
    360 		else if (i == 0)
    361 			break;
    362 		if (sscanf(line, "%u", &u) != 1) {
    363 			printf("Invalid cylinder sector `%s'\n", line);
    364 			continue;
    365 		}
    366 		lp->d_cylskew = u;
    367 		break;
    368 	}
    369 
    370 	/* d_headswitch */
    371 	for (;;) {
    372 		snprintf(def, sizeof(def), "%u", lp->d_headswitch);
    373 		i = getinput(":", "Head switch time (usec)", def, line);
    374 		if (i == -1)
    375 			return;
    376 		else if (i == 0)
    377 			break;
    378 		if (sscanf(line, "%u", &u) != 1) {
    379 			printf("Invalid head switch time `%s'\n", line);
    380 			continue;
    381 		}
    382 		lp->d_headswitch = u;
    383 		break;
    384 	}
    385 
    386 	/* d_trkseek */
    387 	for (;;) {
    388 		snprintf(def, sizeof(def), "%u", lp->d_trkseek);
    389 		i = getinput(":", "Track seek time (usec)", def, line);
    390 		if (i == -1)
    391 			return;
    392 		else if (i == 0)
    393 			break;
    394 		if (sscanf(line, "%u", &u) != 1) {
    395 			printf("Invalid track seek time `%s'\n", line);
    396 			continue;
    397 		}
    398 		lp->d_trkseek = u;
    399 		break;
    400 	}
    401 }
    402 
    403 
    404 static void
    405 cmd_name(struct disklabel *lp, char *s, int fd)
    406 {
    407 	char	line[BUFSIZ];
    408 	char	def[BUFSIZ];
    409 	int	i;
    410 
    411 	snprintf(def, sizeof(def), "%.*s",
    412 	    (int) sizeof(lp->d_packname), lp->d_packname);
    413 	i = getinput(":", "Label name", def, line);
    414 	if (i <= 0)
    415 		return;
    416 	(void) strncpy(lp->d_packname, line, sizeof(lp->d_packname));
    417 }
    418 
    419 
    420 static void
    421 cmd_round(struct disklabel *lp, char *s, int fd)
    422 {
    423 	int	i;
    424 	char	line[BUFSIZ];
    425 
    426 	i = getinput(":", "Rounding", rounding ? "cylinders" : "sectors", line);
    427 	if (i <= 0)
    428 		return;
    429 
    430 	switch (line[0]) {
    431 	case 'c':
    432 	case 'C':
    433 		rounding = 1;
    434 		return;
    435 	case 's':
    436 	case 'S':
    437 		rounding = 0;
    438 		return;
    439 	default:
    440 		printf("Rounding can be (c)ylinders or (s)ectors\n");
    441 		return;
    442 	}
    443 }
    444 
    445 
    446 static void
    447 cmd_part(struct disklabel *lp, char *s, int fd)
    448 {
    449 	int	i;
    450 	char	line[BUFSIZ];
    451 	char	def[BUFSIZ];
    452 	int	part;
    453 	struct partition *p, ps;
    454 
    455 	part = s[0] - 'a';
    456 	p = &lp->d_partitions[part];
    457 	if (part >= lp->d_npartitions)
    458 		lp->d_npartitions = part + 1;
    459 
    460 	(void)memcpy(&ps, p, sizeof(ps));
    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(lp, def, p->p_offset);
    489 		i = getinput(":",
    490 		    "Start offset ('x' to start after partition 'x')",
    491 		    def, line);
    492 		if (i == -1)
    493 			return;
    494 		else if (i == 0)
    495 			break;
    496 		if (line[1] == '\0' &&
    497 	    		line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
    498 			struct partition *cp = lp->d_partitions;
    499 
    500 			if ((cp[line[0] - 'a'].p_offset +
    501 			    cp[line[0] - 'a'].p_size) >= lp->d_secperunit) {
    502 				printf("Bad offset `%s'\n", line);
    503 				continue;
    504 			} else {
    505 				p->p_offset = cp[line[0] - 'a'].p_offset +
    506 				    cp[line[0] - 'a'].p_size;
    507 			}
    508 		} else {
    509 			if ((i = getnum(lp, line, 0)) == -1) {
    510 				printf("Bad offset `%s'\n", line);
    511 				continue;
    512 			} else if (i > lp->d_secperunit) {
    513 				printf("Offset `%s' out of range\n", line);
    514 				continue;
    515 			}
    516 			p->p_offset = i;
    517 		}
    518 		break;
    519 	}
    520 	for (;;) {
    521 		defnum(lp, def, p->p_size);
    522 		i = getinput(":", "Partition size ('$' for all remaining)",
    523 		    def, line);
    524 		if (i == -1)
    525 			return;
    526 		else if (i == 0)
    527 			break;
    528 		if ((i = getnum(lp, line, lp->d_secperunit - p->p_offset))
    529 		    == -1) {
    530 			printf("Bad size `%s'\n", line);
    531 			continue;
    532 		} else if
    533 		    ((i + p->p_offset) > lp->d_secperunit) {
    534 			printf("Size `%s' out of range\n", line);
    535 			continue;
    536 		}
    537 		p->p_size = i;
    538 		break;
    539 	}
    540 
    541 	if (memcmp(&ps, p, sizeof(ps)))
    542 		showpartition(stdout, lp, part, Cflag);
    543 	if (chaining) {
    544 		int offs = -1;
    545 		struct partition *cp = lp->d_partitions;
    546 		for (i = 0; i < lp->d_npartitions; i++) {
    547 			if (cp[i].p_fstype != FS_UNUSED) {
    548 				if (offs != -1 && cp[i].p_offset != offs) {
    549 					cp[i].p_offset = offs;
    550 					showpartition(stdout, lp, i, Cflag);
    551 					}
    552 				offs = cp[i].p_offset + cp[i].p_size;
    553 			}
    554 		}
    555 	}
    556 }
    557 
    558 
    559 static void
    560 cmd_label(struct disklabel *lp, char *s, int fd)
    561 {
    562 	char	line[BUFSIZ];
    563 	int	i;
    564 
    565 	i = getinput("?", "Label disk", "n", line);
    566 	if (i <= 0 || (*line != 'y' && *line != 'Y') )
    567 		return;
    568 
    569 	if (checklabel(lp) != 0) {
    570 		printf("Label not written\n");
    571 		return;
    572 	}
    573 
    574 	if (writelabel(fd, lp) != 0) {
    575 		printf("Label not written\n");
    576 		return;
    577 	}
    578 	printf("Label written\n");
    579 }
    580 
    581 
    582 static int
    583 runcmd(struct disklabel *lp, char *line, int fd)
    584 {
    585 	struct cmds *cmd;
    586 
    587 	for (cmd = cmds; cmd->name != NULL; cmd++)
    588 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
    589 			if (cmd->func == NULL)
    590 				return -1;
    591 			(*cmd->func)(lp, line, fd);
    592 			return 0;
    593 		}
    594 
    595 	if (line[1] == '\0' &&
    596 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
    597 		cmd_part(lp, line, fd);
    598 		return 0;
    599 	}
    600 
    601 	printf("Unknown command %s\n", line);
    602 	return 1;
    603 }
    604 
    605 
    606 static int
    607 getinput(const char *sep, const char *prompt, const char *def, char *line)
    608 {
    609 
    610 	for (;;) {
    611 		printf("%s", prompt);
    612 		if (def)
    613 			printf(" [%s]", def);
    614 		printf("%s ", sep);
    615 
    616 		if (fgets(line, BUFSIZ, stdin) == NULL)
    617 			return -1;
    618 		if (line[0] == '\n' || line[0] == '\0') {
    619 			if (def)
    620 				return 0;
    621 		}
    622 		else {
    623 			char *p;
    624 
    625 			if ((p = strrchr(line, '\n')) != NULL)
    626 				*p = '\0';
    627 			return 1;
    628 		}
    629 	}
    630 }
    631 
    632 static int
    633 alphacmp(const void *a, const void *b)
    634 {
    635 
    636 	return (strcasecmp(*(const char * const*)a, *(const char * const*)b));
    637 }
    638 
    639 
    640 static void
    641 dumpnames(const char *prompt, const char * const *olist, size_t numentries)
    642 {
    643 	int	i, j, w;
    644 	int	columns, width, lines;
    645 	const char *p;
    646 	const char **list;
    647 
    648 	if ((list = (const char **)malloc(sizeof(char *) * numentries)) == NULL)
    649 		err(1, "malloc");
    650 	width = 0;
    651 	printf("%s:\n", prompt);
    652 	for (i = 0; i < numentries; i++) {
    653 		list[i] = olist[i];
    654 		w = strlen(list[i]);
    655 		if (w > width)
    656 			width = w;
    657 	}
    658 #if 0
    659 	for (i = 0; i < numentries; i++)
    660 		printf("%s%s", i == 0 ? "" : ", ", list[i]);
    661 	puts("");
    662 #endif
    663 	(void)qsort(list, numentries, sizeof(char *), alphacmp);
    664 	width++;		/* want two spaces between items */
    665 	width = (width + 8) &~ 7;
    666 
    667 #define ttywidth 72
    668 	columns = ttywidth / width;
    669 #undef ttywidth
    670 	if (columns == 0)
    671 		columns = 1;
    672 	lines = (numentries + columns - 1) / columns;
    673 	for (i = 0; i < lines; i++) {
    674 		for (j = 0; j < columns; j++) {
    675 			p = list[j * lines + i];
    676 			if (j == 0)
    677 				putc('\t', stdout);
    678 			if (p) {
    679 				fputs(p, stdout);
    680 			}
    681 			if (j * lines + i + lines >= numentries) {
    682 				putc('\n', stdout);
    683 				break;
    684 			}
    685 			w = strlen(p);
    686 			while (w < width) {
    687 				w = (w + 8) &~ 7;
    688 				putc('\t', stdout);
    689 			}
    690 		}
    691 	}
    692 	free(list);
    693 }
    694 
    695 
    696 static void
    697 defnum(struct disklabel *lp, char *buf, uint32_t size)
    698 {
    699 
    700 	(void) snprintf(buf, BUFSIZ, "%gc, %us, %gM",
    701 	    size / (float) lp->d_secpercyl,
    702 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
    703 }
    704 
    705 
    706 static int
    707 getnum(struct disklabel *lp, char *buf, int max)
    708 {
    709 	char	*ep;
    710 	double	 d;
    711 	int	 rv;
    712 
    713 	if (max && buf[0] == '$' && buf[1] == 0)
    714 		return max;
    715 
    716 	d = strtod(buf, &ep);
    717 	if (buf == ep)
    718 		return -1;
    719 
    720 #define ROUND(a)	((((a) / lp->d_secpercyl) + \
    721 		 	 (((a) % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl)
    722 
    723 	switch (*ep) {
    724 	case '\0':
    725 	case 's':
    726 	case 'S':
    727 		rv = (int) d;
    728 		break;
    729 
    730 	case 'c':
    731 	case 'C':
    732 		rv = (int) (d * lp->d_secpercyl);
    733 		break;
    734 
    735 	case 'k':
    736 	case 'K':
    737 		rv =  (int) (d * 1024 / lp->d_secsize);
    738 		break;
    739 
    740 	case 'm':
    741 	case 'M':
    742 		rv =  (int) (d * 1024 * 1024 / lp->d_secsize);
    743 		break;
    744 
    745 	case 'g':
    746 	case 'G':
    747 		rv =  (int) (d * 1024 * 1024 * 1024 / lp->d_secsize);
    748 		break;
    749 
    750 	case 't':
    751 	case 'T':
    752 		rv =  (int) (d * 1024 * 1024 * 1024 * 1024 / lp->d_secsize);
    753 		break;
    754 
    755 	default:
    756 		printf("Unit error %c\n", *ep);
    757 		printf("Valid units: (S)ectors, (C)ylinders, (K)ilo, (M)ega, "
    758 		    "(G)iga, (T)era");
    759 		return -1;
    760 	}
    761 
    762 	if (rounding)
    763 		return ROUND(rv);
    764 	else
    765 		return rv;
    766 }
    767 
    768 
    769 void
    770 interact(struct disklabel *lp, int fd)
    771 {
    772 	char	line[BUFSIZ];
    773 
    774 	for (;;) {
    775 		if (getinput(">", "partition", NULL, line) == -1)
    776 			return;
    777 		if (runcmd(lp, line, fd) == -1)
    778 			return;
    779 	}
    780 }
    781