Home | History | Annotate | Line # | Download | only in disklabel
interact.c revision 1.11
      1 /*	$NetBSD: interact.c,v 1.11 1999/11/26 06:03:10 mrg 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.11 1999/11/26 06:03:10 mrg 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 *, 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, 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", def, line);
    449 		if (i <= 0)
    450 			break;
    451 		if ((i = getnum(line, lp)) == -1) {
    452 			printf("Bad size `%s'\n", line);
    453 			continue;
    454 		}
    455 		p->p_size = i;
    456 		break;
    457 	}
    458 
    459 	if (chaining) {
    460 		int offs = p[0].p_offset + p[0].p_size;
    461 		p = lp->d_partitions;
    462 		part = getrawpartition();
    463 		for (i = 1; i < lp->d_npartitions; i++) {
    464 			if (i != part && p[i].p_fstype) {
    465 				p[i].p_offset = offs;
    466 				offs = p[i].p_offset + p[i].p_size;
    467 			}
    468 		}
    469 	}
    470 }
    471 
    472 
    473 static void
    474 cmd_label(lp, s, fd)
    475 	struct disklabel *lp;
    476 	char *s;
    477 	int fd;
    478 {
    479 	char line[BUFSIZ];
    480 	int i;
    481 
    482 	i = getinput("?", "Label disk", "n", line);
    483 
    484 	if (i <= 0 || (*line != 'y' && *line != 'Y') )
    485 		return;
    486 
    487 	if (checklabel(lp) != 0) {
    488 		printf("Label not written\n");
    489 		return;
    490 	}
    491 
    492 	if (writelabel(fd, bootarea, lp) != 0) {
    493 		printf("Label not written\n");
    494 		return;
    495 	}
    496 	printf("Label written\n");
    497 }
    498 
    499 
    500 static int
    501 runcmd(line, lp, fd)
    502 	char *line;
    503 	struct disklabel *lp;
    504 	int fd;
    505 {
    506 	struct cmds *cmd;
    507 
    508 	for (cmd = cmds; cmd->name != NULL; cmd++)
    509 		if (strncmp(line, cmd->name, strlen(cmd->name)) == 0) {
    510 			if (cmd->func == NULL)
    511 				return -1;
    512 			(*cmd->func)(lp, line, fd);
    513 			return 0;
    514 		}
    515 
    516 	if (line[1] == '\0' &&
    517 	    line[0] >= 'a' && line[0] < 'a' + getmaxpartitions()) {
    518 		cmd_part(lp, line, fd);
    519 		return 0;
    520 	}
    521 
    522 	printf("Unknown command %s\n", line);
    523 	return 1;
    524 }
    525 
    526 
    527 static int
    528 getinput(sep, prompt, def, line)
    529 	const char *sep;
    530 	const char *prompt;
    531 	const char *def;
    532 	char *line;
    533 {
    534 	for (;;) {
    535 		printf("%s", prompt);
    536 		if (def)
    537 			printf(" [%s]", def);
    538 		printf("%s ", sep);
    539 
    540 		if (fgets(line, BUFSIZ, stdin) == NULL)
    541 			return -1;
    542 		if (line[0] == '\n' || line[0] == '\0') {
    543 			if (def)
    544 				return 0;
    545 		}
    546 		else {
    547 			char *p;
    548 
    549 			if ((p = strrchr(line, '\n')) != NULL)
    550 				*p = '\0';
    551 			return 1;
    552 		}
    553 	}
    554 }
    555 
    556 
    557 static void
    558 defnum(buf, lp, size)
    559 	char *buf;
    560 	struct disklabel *lp;
    561 	int size;
    562 {
    563 	(void) snprintf(buf, BUFSIZ, "%gc, %ds, %gM",
    564 	    size / (float) lp->d_secpercyl,
    565 	    size, size  * (lp->d_secsize / (float) (1024 * 1024)));
    566 }
    567 
    568 
    569 static int
    570 getnum(buf, lp)
    571 	char *buf;
    572 	struct disklabel *lp;
    573 {
    574 	char *ep;
    575 	double d = strtod(buf, &ep);
    576 	int rv;
    577 
    578 	if (buf == ep)
    579 		return -1;
    580 
    581 #define ROUND(a)	((a / lp->d_secpercyl) + \
    582 			 ((a % lp->d_secpercyl) ? 1 : 0)) * lp->d_secpercyl
    583 
    584 	switch (*ep) {
    585 	case '\0':
    586 	case 's':
    587 		rv = (int) d;
    588 		break;
    589 
    590 	case 'c':
    591 		rv = (int) (d * lp->d_secpercyl);
    592 		break;
    593 
    594 	case 'M':
    595 		rv =  (int) (d * 1024 * 1024 / lp->d_secsize);
    596 		break;
    597 
    598 	default:
    599 		printf("Unit error %c\n", *ep);
    600 		return -1;
    601 	}
    602 
    603 	if (rounding)
    604 		return ROUND(rv);
    605 	else
    606 		return rv;
    607 }
    608 
    609 
    610 static void
    611 deffstypename(buf, i)
    612 	char *buf;
    613 	int i;
    614 {
    615 	if (i < 0 || i >= FSMAXTYPES)
    616 		i = 0;
    617 	(void) strcpy(buf, fstypenames[i]);
    618 }
    619 
    620 
    621 static int
    622 getfstypename(buf)
    623 	const char *buf;
    624 {
    625 	int i;
    626 
    627 	for (i = 0; i < FSMAXTYPES; i++)
    628 		if (strcmp(buf, fstypenames[i]) == 0)
    629 			return i;
    630 	return -1;
    631 }
    632 
    633 
    634 void
    635 interact(lp, fd)
    636 	struct disklabel *lp;
    637 	int fd;
    638 {
    639 	char line[BUFSIZ];
    640 
    641 	for (;;) {
    642 		if (getinput(">", "partition", NULL, line) == -1)
    643 			return;
    644 		if (runcmd(line, lp, fd) == -1)
    645 			return;
    646 	}
    647 }
    648