Home | History | Annotate | Line # | Download | only in disklabel
interact.c revision 1.13
      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