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