1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * This file contains I/O related functions. 29 */ 30 #include "global.h" 31 32 #include <unistd.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <ctype.h> 37 #include <stdarg.h> 38 #include <sys/tty.h> 39 #include <sys/termio.h> 40 #include <sys/termios.h> 41 #include <sys/efi_partition.h> 42 43 #include "startup.h" 44 #include "misc.h" 45 #include "menu_partition.h" 46 #include "param.h" 47 #include "menu.h" 48 49 50 extern int data_lineno; 51 extern char *space2str(uint_t); 52 53 /* 54 * This variable is used to determine whether a token is present in the pipe 55 * already. 56 */ 57 static char token_present = 0; 58 59 /* 60 * This variable always gives us access to the most recent token type 61 */ 62 int last_token_type = 0; 63 64 static int sup_get_token(char *); 65 static void pushchar(int c); 66 static int checkeof(void); 67 static void flushline(void); 68 static int strcnt(char *s1, char *s2); 69 static int getbn(char *str, diskaddr_t *iptr); 70 static void print_input_choices(int type, u_ioparam_t *param); 71 static int slist_widest_str(slist_t *slist); 72 static void ljust_print(char *str, int width); 73 static int sup_inputchar(void); 74 static void sup_pushchar(int c); 75 static int geti64(char *str, uint64_t *iptr, uint64_t *wild); 76 77 /* 78 * This routine pushes the given character back onto the input stream. 79 */ 80 static void 81 pushchar(int c) 82 { 83 (void) ungetc(c, stdin); 84 } 85 86 /* 87 * This routine checks the input stream for an eof condition. 88 */ 89 static int 90 checkeof(void) 91 { 92 return (feof(stdin)); 93 } 94 95 /* 96 * This routine gets the next token off the input stream. A token is 97 * basically any consecutive non-white characters. 98 */ 99 char * 100 gettoken(char *inbuf) 101 { 102 char *ptr = inbuf; 103 int c, quoted = 0; 104 105 retoke: 106 /* 107 * Remove any leading white-space. 108 */ 109 while ((isspace(c = getchar())) && (c != '\n')) 110 ; 111 /* 112 * If we are at the beginning of a line and hit the comment character, 113 * flush the line and start again. 114 */ 115 if (!token_present && c == COMMENT_CHAR) { 116 token_present = 1; 117 flushline(); 118 goto retoke; 119 } 120 /* 121 * Loop on each character until we hit unquoted white-space. 122 */ 123 while (!isspace(c) || (quoted && (c != '\n'))) { 124 /* 125 * If we hit eof, get out. 126 */ 127 if (checkeof()) 128 return (NULL); 129 /* 130 * If we hit a double quote, change the state of quotedness. 131 */ 132 if (c == '"') 133 quoted = !quoted; 134 /* 135 * If there's room in the buffer, add the character to the end. 136 */ 137 else if (ptr - inbuf < TOKEN_SIZE) 138 *ptr++ = (char)c; 139 /* 140 * Get the next character. 141 */ 142 c = getchar(); 143 } 144 /* 145 * Null terminate the token. 146 */ 147 *ptr = '\0'; 148 /* 149 * Peel off white-space still in the pipe. 150 */ 151 while (isspace(c) && (c != '\n')) 152 c = getchar(); 153 /* 154 * If we hit another token, push it back and set state. 155 */ 156 if (c != '\n') { 157 pushchar(c); 158 token_present = 1; 159 } else 160 token_present = 0; 161 /* 162 * Return the token. 163 */ 164 return (inbuf); 165 } 166 167 /* 168 * This routine removes the leading and trailing spaces from a token. 169 */ 170 void 171 clean_token(char *cleantoken, char *token) 172 { 173 char *ptr; 174 175 /* 176 * Strip off leading white-space. 177 */ 178 for (ptr = token; isspace(*ptr); ptr++) 179 ; 180 /* 181 * Copy it into the clean buffer. 182 */ 183 (void) strcpy(cleantoken, ptr); 184 /* 185 * Strip off trailing white-space. 186 */ 187 for (ptr = cleantoken + strlen(cleantoken) - 1; 188 isspace(*ptr) && (ptr >= cleantoken); ptr--) { 189 *ptr = '\0'; 190 } 191 } 192 193 /* 194 * This routine checks if a token is already present on the input line 195 */ 196 int 197 istokenpresent(void) 198 { 199 return (token_present); 200 } 201 202 /* 203 * This routine flushes the rest of an input line if there is known 204 * to be data in it. The flush has to be qualified because the newline 205 * may have already been swallowed by the last gettoken. 206 */ 207 static void 208 flushline(void) 209 { 210 if (token_present) { 211 /* 212 * Flush the pipe to eol or eof. 213 */ 214 while ((getchar() != '\n') && !checkeof()) 215 ; 216 /* 217 * Mark the pipe empty. 218 */ 219 token_present = 0; 220 } 221 } 222 223 /* 224 * This routine returns the number of characters that are identical 225 * between s1 and s2, stopping as soon as a mismatch is found. 226 */ 227 static int 228 strcnt(char *s1, char *s2) 229 { 230 int i = 0; 231 232 while ((*s1 != '\0') && (*s1++ == *s2++)) 233 i++; 234 return (i); 235 } 236 237 /* 238 * This routine converts the given token into an integer. The token 239 * must convert cleanly into an integer with no unknown characters. 240 * If the token is the wildcard string, and the wildcard parameter 241 * is present, the wildcard value will be returned. 242 */ 243 int 244 geti(char *str, int *iptr, int *wild) 245 { 246 char *str2; 247 248 /* 249 * If there's a wildcard value and the string is wild, return the 250 * wildcard value. 251 */ 252 if (wild != NULL && strcmp(str, WILD_STRING) == 0) 253 *iptr = *wild; 254 else { 255 /* 256 * Conver the string to an integer. 257 */ 258 *iptr = (int)strtol(str, &str2, 0); 259 /* 260 * If any characters didn't convert, it's an error. 261 */ 262 if (*str2 != '\0') { 263 err_print("`%s' is not an integer.\n", str); 264 return (-1); 265 } 266 } 267 return (0); 268 } 269 270 /* 271 * This routine converts the given token into a long long. The token 272 * must convert cleanly into a 64-bit integer with no unknown characters. 273 * If the token is the wildcard string, and the wildcard parameter 274 * is present, the wildcard value will be returned. 275 */ 276 static int 277 geti64(char *str, uint64_t *iptr, uint64_t *wild) 278 { 279 char *str2; 280 281 /* 282 * If there's a wildcard value and the string is wild, return the 283 * wildcard value. 284 */ 285 if ((wild != NULL) && (strcmp(str, WILD_STRING)) == 0) { 286 *iptr = *wild; 287 } else { 288 /* 289 * Conver the string to an integer. 290 */ 291 *iptr = (uint64_t)strtoll(str, &str2, 0); 292 /* 293 * If any characters didn't convert, it's an error. 294 */ 295 if (*str2 != '\0') { 296 err_print("`%s' is not an integer.\n", str); 297 return (-1); 298 } 299 } 300 return (0); 301 } 302 303 /* 304 * This routine converts the given string into a block number on the 305 * current disk. The format of a block number is either a self-based 306 * number, or a series of self-based numbers separated by slashes. 307 * Any number preceeding the first slash is considered a cylinder value. 308 * Any number succeeding the first slash but preceeding the second is 309 * considered a head value. Any number succeeding the second slash is 310 * considered a sector value. Any of these numbers can be wildcarded 311 * to the highest possible legal value. 312 */ 313 static int 314 getbn(char *str, diskaddr_t *iptr) 315 { 316 char *cptr, *hptr, *sptr; 317 int cyl, head, sect; 318 int wild; 319 diskaddr_t wild64; 320 TOKEN buf; 321 322 /* 323 * Set cylinder pointer to beginning of string. 324 */ 325 cptr = str; 326 /* 327 * Look for the first slash. 328 */ 329 while ((*str != '\0') && (*str != '/')) 330 str++; 331 /* 332 * If there wasn't one, convert string to an integer and return it. 333 */ 334 if (*str == '\0') { 335 wild64 = physsects() - 1; 336 if (geti64(cptr, iptr, &wild64)) 337 return (-1); 338 return (0); 339 } 340 /* 341 * Null out the slash and set head pointer just beyond it. 342 */ 343 *str++ = '\0'; 344 hptr = str; 345 /* 346 * Look for the second slash. 347 */ 348 while ((*str != '\0') && (*str != '/')) 349 str++; 350 /* 351 * If there wasn't one, sector pointer points to a . 352 */ 353 if (*str == '\0') 354 sptr = str; 355 /* 356 * If there was, null it out and set sector point just beyond it. 357 */ 358 else { 359 *str++ = '\0'; 360 sptr = str; 361 } 362 /* 363 * Convert the cylinder part to an integer and store it. 364 */ 365 clean_token(buf, cptr); 366 wild = ncyl + acyl - 1; 367 if (geti(buf, &cyl, &wild)) 368 return (-1); 369 if ((cyl < 0) || (cyl >= (ncyl + acyl))) { 370 err_print("`%d' is out of range [0-%u].\n", cyl, 371 ncyl + acyl - 1); 372 return (-1); 373 } 374 /* 375 * Convert the head part to an integer and store it. 376 */ 377 clean_token(buf, hptr); 378 wild = nhead - 1; 379 if (geti(buf, &head, &wild)) 380 return (-1); 381 if ((head < 0) || (head >= nhead)) { 382 err_print("`%d' is out of range [0-%u].\n", head, nhead - 1); 383 return (-1); 384 } 385 /* 386 * Convert the sector part to an integer and store it. 387 */ 388 clean_token(buf, sptr); 389 wild = sectors(head) - 1; 390 if (geti(buf, §, &wild)) 391 return (-1); 392 if ((sect < 0) || (sect >= sectors(head))) { 393 err_print("`%d' is out of range [0-%u].\n", sect, 394 sectors(head) - 1); 395 return (-1); 396 } 397 /* 398 * Combine the pieces into a block number and return it. 399 */ 400 *iptr = chs2bn(cyl, head, sect); 401 return (0); 402 } 403 404 /* 405 * This routine is the basis for all input into the program. It 406 * understands the semantics of a set of input types, and provides 407 * consistent error messages for all input. It allows for default 408 * values and prompt strings. 409 */ 410 uint64_t 411 input(int type, char *promptstr, int delim, u_ioparam_t *param, int *deflt, 412 int cmdflag) 413 { 414 int interactive, help, i, length, index, tied; 415 blkaddr_t bn; 416 diskaddr_t bn64; 417 char **str, **strings; 418 TOKEN token, cleantoken; 419 TOKEN token2, cleantoken2; 420 char *arg; 421 struct bounds *bounds; 422 char *s; 423 int value; 424 int cyls, cylno; 425 uint64_t blokno; 426 float nmegs; 427 float ngigs; 428 char shell_argv[MAXPATHLEN]; 429 part_deflt_t *part_deflt; 430 efi_deflt_t *efi_deflt; 431 432 /* 433 * set up pointer to partition defaults structure 434 */ 435 part_deflt = (part_deflt_t *)deflt; 436 efi_deflt = (efi_deflt_t *)deflt; 437 438 /* 439 * Optional integer input has been added as a hack. 440 * Function result is 1 if user typed anything. 441 * Whatever they typed is returned in *deflt. 442 * This permits us to distinguish between "no value", 443 * and actually entering in some value, for instance. 444 */ 445 if (type == FIO_OPINT) { 446 assert(deflt != NULL); 447 } 448 reprompt: 449 help = interactive = 0; 450 /* 451 * If we are inputting a command, flush any current input in the pipe. 452 */ 453 if (cmdflag == CMD_INPUT) 454 flushline(); 455 /* 456 * Note whether the token is already present. 457 */ 458 if (!token_present) 459 interactive = 1; 460 /* 461 * Print the prompt. 462 */ 463 fmt_print(promptstr); 464 /* 465 * If there is a default value, print it in a format appropriate 466 * for the input type. 467 */ 468 if (deflt != NULL) { 469 switch (type) { 470 case FIO_BN: 471 /* caller has aligned the pointer specifying FIO_BN */ 472 fmt_print("[%llu, ", *(diskaddr_t *)deflt); 473 pr_dblock(fmt_print, *(diskaddr_t *)deflt); 474 fmt_print("]"); 475 break; 476 case FIO_INT: 477 fmt_print("[%d]", *deflt); 478 break; 479 case FIO_INT64: 480 fmt_print("[%llu]", efi_deflt->start_sector); 481 break; 482 case FIO_CSTR: 483 case FIO_MSTR: 484 strings = (char **)param->io_charlist; 485 for (i = 0, str = strings; i < *deflt; i++, str++) 486 ; 487 fmt_print("[%s]", *str); 488 break; 489 case FIO_OSTR: 490 fmt_print("[\"%s\"]", (char *)deflt); 491 break; 492 case FIO_SLIST: 493 /* 494 * Search for a string matching the default 495 * value. If found, use it. Otherwise 496 * assume the default value is actually 497 * an illegal choice, and default to 498 * the first item in the list. 499 */ 500 s = find_string(param->io_slist, *deflt); 501 if (s == NULL) { 502 s = (param->io_slist)->str; 503 } 504 fmt_print("[%s]", s); 505 break; 506 case FIO_CYL: 507 /* 508 * Old-style partition size input, used to 509 * modify complete partition tables 510 */ 511 blokno = *(blkaddr32_t *)deflt; 512 fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno, 513 bn2c(blokno), bn2mb(blokno), bn2gb(blokno)); 514 break; 515 case FIO_ECYL: 516 /* 517 * Build print format specifier. We use the 518 * starting cylinder number which was entered 519 * before this call to input(), in case the 520 * user has changed it from the value in the 521 * cur_parts->pinfo_map[].dkl_cylno 522 * field for the current parition 523 */ 524 525 /* 526 * Determine the proper default end cylinder: 527 * Start Cyl Default Size End Cylinder 528 * 0 0 0 529 * >0 0 Start Cyl 530 * 0 >0 Default Size 531 * (Cyls) - 1 532 * >0 >0 (Start + 533 * Default Size 534 * (Cyls)) -1 535 */ 536 537 if (part_deflt->deflt_size == 0) { 538 cylno = part_deflt->start_cyl; 539 } else if (part_deflt->start_cyl == 0) { 540 cylno = bn2c(part_deflt->deflt_size) - 1; 541 } else { 542 cylno = (bn2c(part_deflt->deflt_size) + 543 part_deflt->start_cyl) - 1; 544 } 545 546 fmt_print("[%ub, %uc, %de, %1.2fmb, %1.2fgb]", 547 part_deflt->deflt_size, 548 bn2c(part_deflt->deflt_size), 549 cylno, 550 bn2mb(part_deflt->deflt_size), 551 bn2gb(part_deflt->deflt_size)); 552 553 break; 554 case FIO_EFI: 555 fmt_print("[%llub, %llue, %llumb, %llugb, %llutb]", 556 efi_deflt->end_sector, 557 efi_deflt->start_sector + efi_deflt->end_sector - 1, 558 (efi_deflt->end_sector * cur_blksz) / 559 (1024 * 1024), 560 (efi_deflt->end_sector * cur_blksz) / 561 (1024 * 1024 * 1024), 562 (efi_deflt->end_sector * cur_blksz) / 563 ((uint64_t)1024 * 1024 * 1024 * 1024)); 564 break; 565 case FIO_OPINT: 566 /* no default value for optional input type */ 567 fmt_print("[default]"); 568 break; 569 default: 570 err_print("Error: unknown input type.\n"); 571 fullabort(); 572 } 573 } 574 /* 575 * Print the delimiter character. 576 */ 577 fmt_print("%c ", delim); 578 /* 579 * Get the token. If we hit eof, exit the program gracefully. 580 */ 581 if (gettoken(token) == NULL) 582 fullabort(); 583 584 /* 585 * check if the user has issued (!) , escape to shell 586 */ 587 if ((cmdflag == CMD_INPUT) && (token[0] == '!')) { 588 589 /* get the list of arguments to shell command */ 590 (void) memset(shell_argv, 0, sizeof (shell_argv)); 591 592 /* initialize to the first token... */ 593 arg = &token[1]; 594 595 /* 596 * ... and then collect all tokens until the end of 597 * the line as arguments 598 */ 599 do { 600 /* skip empty tokens. */ 601 if (*arg == '\0') 602 continue; 603 /* 604 * If either of the following two strlcat() 605 * operations overflows, report an error and 606 * exit gracefully. 607 */ 608 if ((strlcat(shell_argv, arg, sizeof (shell_argv)) >= 609 sizeof (shell_argv)) || 610 (strlcat(shell_argv, " ", sizeof (shell_argv)) >= 611 sizeof (shell_argv))) { 612 err_print("Error: Command line too long.\n"); 613 fullabort(); 614 } 615 } while (token_present && (arg = gettoken(token)) != NULL); 616 617 /* execute the shell command */ 618 (void) execute_shell(shell_argv, sizeof (shell_argv)); 619 redisplay_menu_list((char **)param->io_charlist); 620 if (interactive) { 621 goto reprompt; 622 } 623 } 624 625 /* 626 * Certain commands accept up to two tokens 627 * Unfortunately, this is kind of a hack. 628 */ 629 token2[0] = 0; 630 cleantoken2[0] = 0; 631 if (type == FIO_CYL || type == FIO_ECYL) { 632 if (token_present) { 633 if (gettoken(token2) == NULL) 634 fullabort(); 635 clean_token(cleantoken2, token2); 636 } 637 } 638 /* 639 * Echo the token back to the user if it was in the pipe or we 640 * are running out of a command file. 641 */ 642 if (!interactive || option_f) { 643 if (token2[0] == 0) { 644 fmt_print("%s\n", token); 645 } else { 646 fmt_print("%s %s\n", token, token2); 647 } 648 } 649 /* 650 * If we are logging, echo the token to the log file. The else 651 * is necessary here because the above printf will also put the 652 * token in the log file. 653 */ 654 else if (log_file) { 655 log_print("%s %s\n", token, token2); 656 } 657 /* 658 * If the token was not in the pipe and it wasn't a command, flush 659 * the rest of the line to keep things in sync. 660 */ 661 if (interactive && cmdflag != CMD_INPUT) 662 flushline(); 663 /* 664 * Scrub off the white-space. 665 */ 666 clean_token(cleantoken, token); 667 /* 668 * If the input was a blank line and we weren't prompting 669 * specifically for a blank line... 670 */ 671 if ((strcmp(cleantoken, "") == 0) && (type != FIO_BLNK)) { 672 /* 673 * If there's a default, return it. 674 */ 675 if (deflt != NULL) { 676 if (type == FIO_OSTR) { 677 /* 678 * Duplicate and return the default string 679 */ 680 return ((int)alloc_string((char *)deflt)); 681 } else if (type == FIO_SLIST) { 682 /* 683 * If we can find a match for the default 684 * value in the list, return the default 685 * value. If there's no match for the 686 * default value, it's an illegal 687 * choice. Return the first value in 688 * the list. 689 */ 690 s = find_string(param->io_slist, *deflt); 691 if ((cur_label == L_TYPE_EFI) && 692 (s == NULL)) { 693 return (*deflt); 694 } 695 if (s == NULL) { 696 return ((param->io_slist)->value); 697 } else { 698 return (*deflt); 699 } 700 } else if (type == FIO_OPINT) { 701 /* 702 * The user didn't enter anything 703 */ 704 return (0); 705 } else if (type == FIO_ECYL) { 706 return (part_deflt->deflt_size); 707 } else if (type == FIO_INT64) { 708 return (efi_deflt->start_sector); 709 } else if (type == FIO_EFI) { 710 return (efi_deflt->end_sector); 711 } else { 712 return (*deflt); 713 } 714 } 715 /* 716 * If the blank was not in the pipe, just reprompt. 717 */ 718 if (interactive) { 719 goto reprompt; 720 } 721 /* 722 * If the blank was in the pipe, it's an error. 723 */ 724 err_print("No default for this entry.\n"); 725 cmdabort(SIGINT); 726 } 727 /* 728 * If token is a '?' or a 'h', it is a request for help. 729 */ 730 if ((strcmp(cleantoken, "?") == 0) || 731 (strcmp(cleantoken, "h") == 0) || 732 (strcmp(cleantoken, "help") == 0)) { 733 help = 1; 734 } 735 /* 736 * Switch on the type of input expected. 737 */ 738 switch (type) { 739 /* 740 * Expecting a disk block number. 741 */ 742 case FIO_BN: 743 /* 744 * Parameter is the bounds of legal block numbers. 745 */ 746 bounds = (struct bounds *)¶m->io_bounds; 747 /* 748 * Print help message if required. 749 */ 750 if (help) { 751 fmt_print("Expecting a block number from %llu (", 752 bounds->lower); 753 pr_dblock(fmt_print, bounds->lower); 754 fmt_print(") to %llu (", bounds->upper); 755 pr_dblock(fmt_print, bounds->upper); 756 fmt_print(")\n"); 757 break; 758 } 759 /* 760 * Convert token to a disk block number. 761 */ 762 if (cur_label == L_TYPE_EFI) { 763 if (geti64(cleantoken, (uint64_t *)&bn64, NULL)) 764 break; 765 } else { 766 if (getbn(cleantoken, &bn64)) 767 break; 768 } 769 /* 770 * Check to be sure it is within the legal bounds. 771 */ 772 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) { 773 err_print("`"); 774 pr_dblock(err_print, bn64); 775 err_print("' is out of range [%llu-%llu].\n", 776 bounds->lower, bounds->upper); 777 break; 778 } 779 /* 780 * It's ok, return it. 781 */ 782 return (bn64); 783 /* 784 * Expecting an integer. 785 */ 786 case FIO_INT: 787 /* 788 * Parameter is the bounds of legal integers. 789 */ 790 bounds = (struct bounds *)¶m->io_bounds; 791 /* 792 * Print help message if required. 793 */ 794 if (help) { 795 fmt_print("Expecting an integer from %llu", 796 bounds->lower); 797 fmt_print(" to %llu\n", bounds->upper); 798 break; 799 } 800 /* 801 * Convert the token into an integer. 802 */ 803 if (geti(cleantoken, (int *)&bn, NULL)) 804 break; 805 /* 806 * Check to be sure it is within the legal bounds. 807 */ 808 if ((bn < bounds->lower) || (bn > bounds->upper)) { 809 err_print("`%lu' is out of range [%llu-%llu].\n", bn, 810 bounds->lower, bounds->upper); 811 break; 812 } 813 /* 814 * If it's ok, return it. 815 */ 816 return (bn); 817 case FIO_INT64: 818 /* 819 * Parameter is the bounds of legal integers. 820 */ 821 bounds = (struct bounds *)¶m->io_bounds; 822 /* 823 * Print help message if required. 824 */ 825 if (help) { 826 fmt_print("Expecting an integer from %llu", 827 bounds->lower); 828 fmt_print(" to %llu\n", bounds->upper); 829 break; 830 } 831 /* 832 * Convert the token into an integer. 833 */ 834 if (geti64(cleantoken, (uint64_t *)&bn64, NULL)) { 835 break; 836 } 837 /* 838 * Check to be sure it is within the legal bounds. 839 */ 840 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) { 841 err_print("`%llu' is out of range [%llu-%llu].\n", 842 bn64, bounds->lower, bounds->upper); 843 break; 844 } 845 /* 846 * If it's ok, return it. 847 */ 848 return (bn64); 849 /* 850 * Expecting an integer, or no input. 851 */ 852 case FIO_OPINT: 853 /* 854 * Parameter is the bounds of legal integers. 855 */ 856 bounds = (struct bounds *)¶m->io_bounds; 857 /* 858 * Print help message if required. 859 */ 860 if (help) { 861 fmt_print("Expecting an integer from %llu", 862 bounds->lower); 863 fmt_print(" to %llu, or no input\n", bounds->upper); 864 break; 865 } 866 /* 867 * Convert the token into an integer. 868 */ 869 if (geti(cleantoken, (int *)&bn, NULL)) 870 break; 871 /* 872 * Check to be sure it is within the legal bounds. 873 */ 874 if ((bn < bounds->lower) || (bn > bounds->upper)) { 875 err_print("`%lu' is out of range [%llu-%llu].\n", bn, 876 bounds->lower, bounds->upper); 877 break; 878 } 879 /* 880 * For optional case, return 1 indicating that 881 * the user actually did enter something. 882 */ 883 if (!deflt) 884 *deflt = bn; 885 return (1); 886 /* 887 * Expecting a closed string. This means that the input 888 * string must exactly match one of the strings passed in 889 * as the parameter. 890 */ 891 case FIO_CSTR: 892 /* 893 * The parameter is a null terminated array of character 894 * pointers, each one pointing to a legal input string. 895 */ 896 strings = (char **)param->io_charlist; 897 /* 898 * Walk through the legal strings, seeing if any of them 899 * match the token. If a match is made, return the index 900 * of the string that was matched. 901 */ 902 for (str = strings; *str != NULL; str++) 903 if (strcmp(cleantoken, *str) == 0) 904 return (str - strings); 905 /* 906 * Print help message if required. 907 */ 908 if (help) { 909 print_input_choices(type, param); 910 } else { 911 err_print("`%s' is not expected.\n", cleantoken); 912 } 913 break; 914 /* 915 * Expecting a matched string. This means that the input 916 * string must either match one of the strings passed in, 917 * or be a unique abbreviation of one of them. 918 */ 919 case FIO_MSTR: 920 /* 921 * The parameter is a null terminated array of character 922 * pointers, each one pointing to a legal input string. 923 */ 924 strings = (char **)param->io_charlist; 925 length = index = tied = 0; 926 /* 927 * Loop through the legal input strings. 928 */ 929 for (str = strings; *str != NULL; str++) { 930 /* 931 * See how many characters of the token match 932 * this legal string. 933 */ 934 i = strcnt(cleantoken, *str); 935 /* 936 * If it's not the whole token, then it's not a match. 937 */ 938 if ((uint_t)i < strlen(cleantoken)) 939 continue; 940 /* 941 * If it ties with another input, remember that. 942 */ 943 if (i == length) 944 tied = 1; 945 /* 946 * If it matches the most so far, record that. 947 */ 948 if (i > length) { 949 index = str - strings; 950 tied = 0; 951 length = i; 952 } 953 } 954 /* 955 * Print help message if required. 956 */ 957 if (length == 0) { 958 if (help) { 959 print_input_choices(type, param); 960 } else { 961 err_print("`%s' is not expected.\n", 962 cleantoken); 963 } 964 break; 965 } 966 /* 967 * If the abbreviation was non-unique, it's an error. 968 */ 969 if (tied) { 970 err_print("`%s' is ambiguous.\n", cleantoken); 971 break; 972 } 973 /* 974 * We matched one. Return the index of the string we matched. 975 */ 976 return (index); 977 /* 978 * Expecting an open string. This means that any string is legal. 979 */ 980 case FIO_OSTR: 981 /* 982 * Print a help message if required. 983 */ 984 if (help) { 985 fmt_print("Expecting a string\n"); 986 break; 987 } 988 /* 989 * alloc a copy of the string and return it 990 */ 991 return ((int)alloc_string(token)); 992 993 /* 994 * Expecting a blank line. 995 */ 996 case FIO_BLNK: 997 /* 998 * We are always in non-echo mode when we are inputting 999 * this type. We echo the newline as a carriage return 1000 * only so the prompt string will be covered over. 1001 */ 1002 nolog_print("\015"); 1003 /* 1004 * If we are logging, send a newline to the log file. 1005 */ 1006 if (log_file) 1007 log_print("\n"); 1008 /* 1009 * There is no value returned for this type. 1010 */ 1011 return (0); 1012 1013 /* 1014 * Expecting one of the entries in a string list. 1015 * Accept unique abbreviations. 1016 * Return the value associated with the matched string. 1017 */ 1018 case FIO_SLIST: 1019 i = find_value((slist_t *)param->io_slist, cleantoken, &value); 1020 if (i == 1) { 1021 return (value); 1022 } else { 1023 /* 1024 * Print help message if required. 1025 */ 1026 1027 if (help) { 1028 print_input_choices(type, param); 1029 } else { 1030 if (i == 0) 1031 err_print("`%s' not expected.\n", 1032 cleantoken); 1033 else 1034 err_print("`%s' is ambiguous.\n", 1035 cleantoken); 1036 } 1037 } 1038 break; 1039 1040 /* 1041 * Cylinder size input when modifying a complete partition map 1042 */ 1043 case FIO_CYL: 1044 /* 1045 * Parameter is the bounds of legal block numbers. 1046 */ 1047 bounds = (struct bounds *)¶m->io_bounds; 1048 assert(bounds->lower == 0); 1049 /* 1050 * Print help message if required. 1051 */ 1052 if (help) { 1053 fmt_print("Expecting up to %llu blocks,", 1054 bounds->upper); 1055 fmt_print(" %u cylinders, ", bn2c(bounds->upper)); 1056 fmt_print(" %1.2f megabytes, ", bn2mb(bounds->upper)); 1057 fmt_print("or %1.2f gigabytes\n", bn2gb(bounds->upper)); 1058 break; 1059 } 1060 /* 1061 * Parse the first token: try to find 'b', 'c' or 'm' 1062 */ 1063 s = cleantoken; 1064 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) { 1065 s++; 1066 } 1067 /* 1068 * If we found a conversion specifier, second token is unused 1069 * Otherwise, the second token should supply it. 1070 */ 1071 if (*s != 0) { 1072 value = *s; 1073 *s = 0; 1074 } else { 1075 value = cleantoken2[0]; 1076 } 1077 /* 1078 * If the token is the wild card, simply supply the max 1079 * This order allows the user to specify the maximum in 1080 * either blocks/cyls/megabytes - a convenient fiction. 1081 */ 1082 if (strcmp(cleantoken, WILD_STRING) == 0) { 1083 return (bounds->upper); 1084 } 1085 /* 1086 * Allow the user to specify zero with no units, 1087 * by just defaulting to cylinders. 1088 */ 1089 if (strcmp(cleantoken, "0") == 0) { 1090 value = 'c'; 1091 } 1092 /* 1093 * If there's a decimal point, but no unit specification, 1094 * let's assume megabytes. 1095 */ 1096 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) { 1097 value = 'm'; 1098 } 1099 /* 1100 * Handle each unit type we support 1101 */ 1102 switch (value) { 1103 case 'b': 1104 /* 1105 * Convert token to a disk block number. 1106 */ 1107 if (geti64(cleantoken, &bn64, &bounds->upper)) 1108 break; 1109 /* 1110 * Check to be sure it is within the legal bounds. 1111 */ 1112 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) { 1113 err_print( 1114 "`%llub' is out of the range %llu " 1115 "to %llu\n", 1116 bn64, bounds->lower, bounds->upper); 1117 break; 1118 } 1119 /* 1120 * Verify the block lies on a cylinder boundary 1121 */ 1122 if ((bn64 % spc()) != 0) { 1123 err_print( 1124 "partition size must be a multiple of " 1125 "%u blocks to lie on a cylinder boundary\n", 1126 spc()); 1127 err_print( 1128 "%llu blocks is approximately %u cylinders," 1129 " %1.2f megabytes or %1.2f gigabytes\n", 1130 bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64)); 1131 break; 1132 } 1133 return (bn64); 1134 case 'c': 1135 /* 1136 * Convert token from a number of cylinders to 1137 * a number of blocks. 1138 */ 1139 i = bn2c(bounds->upper); 1140 if (geti(cleantoken, &cyls, &i)) 1141 break; 1142 /* 1143 * Check the bounds - cyls is number of cylinders 1144 */ 1145 if (cyls > (bounds->upper / spc())) { 1146 err_print("`%dc' is out of range [0-%llu]\n", 1147 cyls, bounds->upper / spc()); 1148 break; 1149 } 1150 /* 1151 * Convert cylinders to blocks and return 1152 */ 1153 return (cyls * spc()); 1154 case 'm': 1155 /* 1156 * Convert token from megabytes to a block number. 1157 */ 1158 if (sscanf(cleantoken, "%f2", &nmegs) != 1) { 1159 err_print("`%s' is not recognized\n", 1160 cleantoken); 1161 break; 1162 } 1163 /* 1164 * Check the bounds 1165 */ 1166 if (nmegs > bn2mb(bounds->upper)) { 1167 err_print("`%1.2fmb' is out of range " 1168 "[0-%1.2f]\n", nmegs, bn2mb(bounds->upper)); 1169 break; 1170 } 1171 /* 1172 * Convert to blocks 1173 */ 1174 bn64 = mb2bn(nmegs); 1175 /* 1176 * Round value up to nearest cylinder 1177 */ 1178 i = spc(); 1179 bn64 = ((bn64 + (i-1)) / i) * i; 1180 return (bn64); 1181 case 'g': 1182 /* 1183 * Convert token from gigabytes to a block number. 1184 */ 1185 if (sscanf(cleantoken, "%f2", &ngigs) != 1) { 1186 err_print("`%s' is not recognized\n", 1187 cleantoken); 1188 break; 1189 } 1190 /* 1191 * Check the bounds 1192 */ 1193 if (ngigs > bn2gb(bounds->upper)) { 1194 err_print("`%1.2fgb' is out of range " 1195 "[0-%1.2f]\n", ngigs, bn2gb(bounds->upper)); 1196 break; 1197 } 1198 /* 1199 * Convert to blocks 1200 */ 1201 bn64 = gb2bn(ngigs); 1202 /* 1203 * Round value up to nearest cylinder 1204 */ 1205 i = spc(); 1206 bn64 = ((bn64 + (i-1)) / i) * i; 1207 return (bn64); 1208 default: 1209 err_print( 1210 "Please specify units in either b(blocks), c(cylinders), m(megabytes) \ 1211 or g(gigabytes)\n"); 1212 break; 1213 } 1214 break; 1215 1216 case FIO_ECYL: 1217 /* 1218 * Parameter is the bounds of legal block numbers. 1219 */ 1220 bounds = (struct bounds *)¶m->io_bounds; 1221 assert(bounds->lower == 0); 1222 1223 /* 1224 * Print help message if required. 1225 */ 1226 if (help) { 1227 fmt_print("Expecting up to %llu blocks,", 1228 bounds->upper); 1229 fmt_print(" %u cylinders, ", 1230 bn2c(bounds->upper)); 1231 fmt_print(" %u end cylinder, ", 1232 (uint_t)(bounds->upper / spc())); 1233 fmt_print(" %1.2f megabytes, ", 1234 bn2mb(bounds->upper)); 1235 fmt_print("or %1.2f gigabytes\n", 1236 bn2gb(bounds->upper)); 1237 break; 1238 } 1239 1240 /* 1241 * Parse the first token: try to find 'b', 'c', 'e' 1242 * or 'm' 1243 */ 1244 s = cleantoken; 1245 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) { 1246 s++; 1247 } 1248 1249 /* 1250 * If we found a conversion specifier, second token is 1251 * unused Otherwise, the second token should supply it. 1252 */ 1253 if (*s != 0) { 1254 value = *s; 1255 *s = 0; 1256 } else { 1257 value = cleantoken2[0]; 1258 } 1259 1260 /* 1261 * If the token is the wild card, simply supply the max 1262 * This order allows the user to specify the maximum in 1263 * either blocks/cyls/megabytes - a convenient fiction. 1264 */ 1265 if (strcmp(cleantoken, WILD_STRING) == 0) { 1266 return (bounds->upper); 1267 } 1268 1269 /* 1270 * Allow the user to specify zero with no units, 1271 * by just defaulting to cylinders. 1272 */ 1273 1274 if (value != 'e' && strcmp(cleantoken, "0") == 0) { 1275 value = 'c'; 1276 } 1277 1278 1279 /* 1280 * If there's a decimal point, but no unit 1281 * specification, let's assume megabytes. 1282 */ 1283 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) { 1284 value = 'm'; 1285 } 1286 1287 /* 1288 * Handle each unit type we support 1289 */ 1290 switch (value) { 1291 case 'b': 1292 /* 1293 * Convert token to a disk block number. 1294 */ 1295 if (geti64(cleantoken, &bn64, &bounds->upper)) 1296 break; 1297 /* 1298 * Check to be sure it is within the 1299 * legal bounds. 1300 */ 1301 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) { 1302 err_print( 1303 "`%llub' is out of the range %llu to %llu\n", 1304 bn64, bounds->lower, bounds->upper); 1305 break; 1306 } 1307 1308 /* 1309 * Verify the block lies on a cylinder 1310 * boundary 1311 */ 1312 if ((bn64 % spc()) != 0) { 1313 err_print( 1314 "partition size must be a multiple of %u " 1315 "blocks to lie on a cylinder boundary\n", 1316 spc()); 1317 err_print( 1318 "%llu blocks is approximately %u cylinders," 1319 " %1.2f megabytes or %1.2f gigabytes\n", 1320 bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64)); 1321 break; 1322 } 1323 1324 return (bn64); 1325 1326 case 'e': 1327 /* 1328 * Token is ending cylinder 1329 */ 1330 1331 /* convert token to integer */ 1332 if (geti(cleantoken, &cylno, NULL)) { 1333 break; 1334 } 1335 1336 /* 1337 * check that input cylno isn't before the current 1338 * starting cylinder number. Note that we are NOT 1339 * using the starting cylinder from 1340 * cur_parts->pinfo_map[].dkl_cylno! 1341 */ 1342 if (cylno < part_deflt->start_cyl) { 1343 err_print( 1344 "End cylinder must fall on or after start cylinder %u\n", 1345 part_deflt->start_cyl); 1346 break; 1347 } 1348 1349 /* 1350 * calculate cylinder number of upper boundary, and 1351 * verify that our input is within range 1352 */ 1353 i = (bn2c(bounds->upper) + part_deflt->start_cyl - 1); 1354 1355 if (cylno > i) { 1356 err_print( 1357 "End cylinder %d is beyond max cylinder %d\n", 1358 cylno, i); 1359 break; 1360 } 1361 1362 /* 1363 * calculate number of cylinders based on input 1364 */ 1365 cyls = ((cylno - part_deflt->start_cyl) + 1); 1366 1367 return (cyls * spc()); 1368 1369 case 'c': 1370 /* 1371 * Convert token from a number of 1372 * cylinders to a number of blocks. 1373 */ 1374 i = bn2c(bounds->upper); 1375 if (geti(cleantoken, &cyls, &i)) 1376 break; 1377 1378 /* 1379 * Check the bounds - cyls is number of 1380 * cylinders 1381 */ 1382 if (cyls > (bounds->upper / spc())) { 1383 err_print("`%dc' is out of range [0-%llu]\n", 1384 cyls, bounds->upper / spc()); 1385 break; 1386 } 1387 1388 /* 1389 * Convert cylinders to blocks and 1390 * return 1391 */ 1392 return (cyls * spc()); 1393 1394 case 'm': 1395 /* 1396 * Convert token from megabytes to a 1397 * block number. 1398 */ 1399 if (sscanf(cleantoken, "%f2", &nmegs) != 1) { 1400 err_print("`%s' is not recognized\n", 1401 cleantoken); 1402 break; 1403 } 1404 1405 /* 1406 * Check the bounds 1407 */ 1408 if (nmegs > bn2mb(bounds->upper)) { 1409 err_print("`%1.2fmb' is out of range " 1410 "[0-%1.2f]\n", nmegs, bn2mb(bounds->upper)); 1411 break; 1412 } 1413 1414 /* 1415 * Convert to blocks 1416 */ 1417 bn64 = mb2bn(nmegs); 1418 1419 /* 1420 * Round value up to nearest cylinder 1421 */ 1422 i = spc(); 1423 bn64 = ((bn64 + (i-1)) / i) * i; 1424 return (bn64); 1425 1426 case 'g': 1427 /* 1428 * Convert token from gigabytes to a 1429 * block number. 1430 */ 1431 if (sscanf(cleantoken, "%f2", &ngigs) != 1) { 1432 err_print("`%s' is not recognized\n", 1433 cleantoken); 1434 break; 1435 } 1436 1437 /* 1438 * Check the bounds 1439 */ 1440 if (ngigs > bn2gb(bounds->upper)) { 1441 err_print("`%1.2fgb' is out of range " 1442 "[0-%1.2f]\n", ngigs, bn2gb(bounds->upper)); 1443 break; 1444 } 1445 1446 /* 1447 * Convert to blocks 1448 */ 1449 bn64 = gb2bn(ngigs); 1450 1451 /* 1452 * Round value up to nearest cylinder 1453 */ 1454 i = spc(); 1455 bn64 = ((bn64 + (i-1)) / i) * i; 1456 return (bn64); 1457 1458 default: 1459 err_print( 1460 "Please specify units in either b(blocks), c(cylinders), e(end cylinder),\n"); 1461 err_print("m(megabytes) or g(gigabytes)\n"); 1462 break; 1463 } 1464 break; 1465 case FIO_EFI: 1466 /* 1467 * Parameter is the bounds of legal block numbers. 1468 */ 1469 bounds = (struct bounds *)¶m->io_bounds; 1470 1471 /* 1472 * Print help message if required. 1473 */ 1474 if (help) { 1475 fmt_print("Expecting up to %llu sectors,", 1476 cur_parts->etoc->efi_last_u_lba); 1477 fmt_print("or %llu megabytes,", 1478 (cur_parts->etoc->efi_last_u_lba * cur_blksz) / 1479 (1024 * 1024)); 1480 fmt_print("or %llu gigabytes\n", 1481 (cur_parts->etoc->efi_last_u_lba * cur_blksz) / 1482 (1024 * 1024 * 1024)); 1483 fmt_print("or %llu terabytes\n", 1484 (cur_parts->etoc->efi_last_u_lba * cur_blksz) / 1485 ((uint64_t)1024 * 1024 * 1024 * 1024)); 1486 break; 1487 } 1488 1489 /* 1490 * Parse the first token: try to find 'b', 'c', 'e' 1491 * or 'm' 1492 */ 1493 s = cleantoken; 1494 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) { 1495 s++; 1496 } 1497 1498 /* 1499 * If we found a conversion specifier, second token is 1500 * unused Otherwise, the second token should supply it. 1501 */ 1502 if (*s != 0) { 1503 value = *s; 1504 *s = 0; 1505 } else { 1506 value = cleantoken2[0]; 1507 } 1508 1509 /* 1510 * If the token is the wild card, simply supply the max 1511 * This order allows the user to specify the maximum in 1512 * either blocks/cyls/megabytes - a convenient fiction. 1513 */ 1514 if (strcmp(cleantoken, WILD_STRING) == 0) { 1515 uint64_t reserved; 1516 1517 reserved = efi_reserved_sectors(cur_parts->etoc); 1518 return (bounds->upper - reserved - 1519 efi_deflt->start_sector + 1); 1520 } 1521 1522 /* 1523 * Allow the user to specify zero with no units, 1524 * by just defaulting to sectors. 1525 */ 1526 1527 if (value != 'e' && strcmp(cleantoken, "0") == 0) { 1528 value = 'm'; 1529 } 1530 1531 1532 /* 1533 * If there's a decimal point, but no unit 1534 * specification, let's assume megabytes. 1535 */ 1536 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) { 1537 value = 'm'; 1538 } 1539 1540 /* 1541 * Handle each unit type we support 1542 */ 1543 switch (value) { 1544 case 'b': 1545 /* 1546 * Token is number of blocks 1547 */ 1548 if (geti64(cleantoken, &blokno, NULL)) { 1549 break; 1550 } 1551 if (blokno > bounds->upper) { 1552 err_print("Number of blocks must be less that " 1553 "the total available blocks.\n"); 1554 break; 1555 } 1556 return (blokno); 1557 1558 case 'e': 1559 /* 1560 * Token is ending block number 1561 */ 1562 1563 /* convert token to integer */ 1564 if (geti64(cleantoken, &blokno, NULL)) { 1565 break; 1566 } 1567 1568 /* 1569 * Some sanity check 1570 */ 1571 if (blokno < efi_deflt->start_sector) { 1572 err_print("End Sector must fall on or after " 1573 "start sector %llu\n", 1574 efi_deflt->start_sector); 1575 break; 1576 } 1577 1578 /* 1579 * verify that our input is within range 1580 */ 1581 if (blokno > cur_parts->etoc->efi_last_u_lba) { 1582 err_print("End Sector %llu is beyond max " 1583 "Sector %llu\n", 1584 blokno, cur_parts->etoc->efi_last_u_lba); 1585 break; 1586 } 1587 1588 /* 1589 * calculate number of blocks based on input 1590 */ 1591 1592 return (blokno - efi_deflt->start_sector + 1); 1593 1594 case 'm': 1595 /* 1596 * Convert token from megabytes to a 1597 * block number. 1598 */ 1599 if (sscanf(cleantoken, "%f2", &nmegs) != 1) { 1600 err_print("`%s' is not recognized\n", 1601 cleantoken); 1602 break; 1603 } 1604 1605 /* 1606 * Check the bounds 1607 */ 1608 if (nmegs > bn2mb(bounds->upper - bounds->lower)) { 1609 err_print("`%1.2fmb' is out of range " 1610 "[0-%1.2f]\n", nmegs, 1611 bn2mb(bounds->upper - bounds->lower)); 1612 break; 1613 } 1614 1615 return (mb2bn(nmegs)); 1616 1617 case 'g': 1618 if (sscanf(cleantoken, "%f2", &nmegs) != 1) { 1619 err_print("`%s' is not recognized\n", 1620 cleantoken); 1621 break; 1622 } 1623 if (nmegs > bn2gb(bounds->upper - bounds->lower)) { 1624 err_print("`%1.2fgb' is out of range " 1625 "[0-%1.2f]\n", nmegs, 1626 bn2gb(bounds->upper - bounds->lower)); 1627 break; 1628 } 1629 1630 return (gb2bn(nmegs)); 1631 1632 case 't': 1633 if (sscanf(cleantoken, "%f2", &nmegs) != 1) { 1634 err_print("`%s' is not recognized\n", 1635 cleantoken); 1636 break; 1637 } 1638 if (nmegs > bn2tb(bounds->upper - bounds->lower)) { 1639 err_print("`%1.2ftb' is out of range " 1640 "[0-%1.2f]\n", nmegs, 1641 bn2tb(bounds->upper - bounds->lower)); 1642 break; 1643 } 1644 return (uint64_t)((float)nmegs * 1024.0 * 1645 1024.0 * 1024.0 * 1024.0 / cur_blksz); 1646 1647 default: 1648 err_print("Please specify units in either " 1649 "b(number of blocks), e(end sector),\n"); 1650 err_print(" g(gigabytes), m(megabytes)"); 1651 err_print(" or t(terabytes)\n"); 1652 break; 1653 } 1654 break; 1655 1656 /* 1657 * If we don't recognize the input type, it's bad news. 1658 */ 1659 default: 1660 err_print("Error: unknown input type.\n"); 1661 fullabort(); 1662 } 1663 /* 1664 * If we get here, it's because some error kept us from accepting 1665 * the token. If we are running out of a command file, gracefully 1666 * leave the program. If we are interacting with the user, simply 1667 * reprompt. If the token was in the pipe, abort the current command. 1668 */ 1669 if (option_f) 1670 fullabort(); 1671 else if (interactive) 1672 goto reprompt; 1673 else 1674 cmdabort(SIGINT); 1675 /* 1676 * Never actually reached. 1677 */ 1678 return (-1); 1679 } 1680 1681 /* 1682 * Print input choices 1683 */ 1684 static void 1685 print_input_choices(int type, u_ioparam_t *param) 1686 { 1687 char **sp; 1688 slist_t *lp; 1689 int width; 1690 int col; 1691 int ncols; 1692 1693 switch (type) { 1694 case FIO_CSTR: 1695 fmt_print("Expecting one of the following:\n"); 1696 goto common; 1697 1698 case FIO_MSTR: 1699 fmt_print("Expecting one of the following: "); 1700 fmt_print("(abbreviations ok):\n"); 1701 common: 1702 for (sp = (char **)param->io_charlist; *sp != NULL; sp++) { 1703 fmt_print("\t%s\n", *sp); 1704 } 1705 break; 1706 1707 case FIO_SLIST: 1708 fmt_print("Expecting one of the following: "); 1709 fmt_print("(abbreviations ok):\n"); 1710 /* 1711 * Figure out the width of the widest string 1712 */ 1713 width = slist_widest_str((slist_t *)param->io_slist); 1714 width += 4; 1715 /* 1716 * If the help messages are empty, print the 1717 * possible choices in left-justified columns 1718 */ 1719 lp = (slist_t *)param->io_slist; 1720 if (*lp->help == 0) { 1721 col = 0; 1722 ncols = 60 / width; 1723 for (; lp->str != NULL; lp++) { 1724 if (col == 0) 1725 fmt_print("\t"); 1726 ljust_print(lp->str, 1727 (++col == ncols) ? 0 : width); 1728 if (col == ncols) { 1729 col = 0; 1730 fmt_print("\n"); 1731 } 1732 } 1733 if (col != 0) 1734 fmt_print("\n"); 1735 } else { 1736 /* 1737 * With help messages, print each choice, 1738 * and help message, on its own line. 1739 */ 1740 for (; lp->str != NULL; lp++) { 1741 fmt_print("\t"); 1742 ljust_print(lp->str, width); 1743 fmt_print("- %s\n", lp->help); 1744 } 1745 } 1746 break; 1747 1748 default: 1749 err_print("Error: unknown input type.\n"); 1750 fullabort(); 1751 } 1752 1753 fmt_print("\n"); 1754 } 1755 1756 1757 /* 1758 * Search a string list for a particular string. 1759 * Use minimum recognition, to accept unique abbreviations 1760 * Return the number of possible matches found. 1761 * If only one match was found, return the arbitrary value 1762 * associated with the matched string in match_value. 1763 */ 1764 int 1765 find_value(slist_t *slist, char *match_str, int *match_value) 1766 { 1767 int i; 1768 int nmatches; 1769 int length; 1770 int match_length; 1771 1772 nmatches = 0; 1773 length = 0; 1774 1775 match_length = strlen(match_str); 1776 1777 for (; slist->str != NULL; slist++) { 1778 /* 1779 * See how many characters of the token match 1780 */ 1781 i = strcnt(match_str, slist->str); 1782 /* 1783 * If it's not the whole token, then it's not a match. 1784 */ 1785 if (i < match_length) 1786 continue; 1787 /* 1788 * If it ties with another input, remember that. 1789 */ 1790 if (i == length) 1791 nmatches++; 1792 /* 1793 * If it matches the most so far, record that. 1794 */ 1795 if (i > length) { 1796 *match_value = slist->value; 1797 nmatches = 1; 1798 length = i; 1799 } 1800 } 1801 1802 return (nmatches); 1803 } 1804 1805 /* 1806 * Search a string list for a particular value. 1807 * Return the string associated with that value. 1808 */ 1809 char * 1810 find_string(slist_t *slist, int match_value) 1811 { 1812 for (; slist->str != NULL; slist++) { 1813 if (slist->value == match_value) { 1814 return (slist->str); 1815 } 1816 } 1817 1818 return (NULL); 1819 } 1820 1821 /* 1822 * Return the width of the widest string in an slist 1823 */ 1824 static int 1825 slist_widest_str(slist_t *slist) 1826 { 1827 int i; 1828 int width; 1829 1830 width = 0; 1831 for (; slist->str != NULL; slist++) { 1832 if ((i = strlen(slist->str)) > width) 1833 width = i; 1834 } 1835 1836 return (width); 1837 } 1838 1839 /* 1840 * Print a string left-justified to a fixed width. 1841 */ 1842 static void 1843 ljust_print(char *str, int width) 1844 { 1845 int i; 1846 1847 fmt_print("%s", str); 1848 for (i = width - strlen(str); i > 0; i--) { 1849 fmt_print(" "); 1850 } 1851 } 1852 1853 /* 1854 * This routine is a modified version of printf. It handles the cases 1855 * of silent mode and logging; other than that it is identical to the 1856 * library version. 1857 */ 1858 /*PRINTFLIKE1*/ 1859 void 1860 fmt_print(char *format, ...) 1861 { 1862 va_list ap; 1863 1864 va_start(ap, format); 1865 1866 /* 1867 * If we are running silent, skip it. 1868 */ 1869 if (option_s == 0) { 1870 /* 1871 * Do the print to standard out. 1872 */ 1873 if (need_newline) { 1874 (void) printf("\n"); 1875 } 1876 (void) vprintf(format, ap); 1877 /* 1878 * If we are logging, also print to the log file. 1879 */ 1880 if (log_file) { 1881 if (need_newline) { 1882 (void) fprintf(log_file, "\n"); 1883 } 1884 (void) vfprintf(log_file, format, ap); 1885 (void) fflush(log_file); 1886 } 1887 } 1888 1889 need_newline = 0; 1890 1891 va_end(ap); 1892 } 1893 1894 /* 1895 * This routine is a modified version of printf. It handles the cases 1896 * of silent mode; other than that it is identical to the 1897 * library version. It differs from the above printf in that it does 1898 * not print the message to a log file. 1899 */ 1900 /*PRINTFLIKE1*/ 1901 void 1902 nolog_print(char *format, ...) 1903 { 1904 va_list ap; 1905 1906 va_start(ap, format); 1907 1908 /* 1909 * If we are running silent, skip it. 1910 */ 1911 if (option_s == 0) { 1912 /* 1913 * Do the print to standard out. 1914 */ 1915 if (need_newline) { 1916 (void) printf("\n"); 1917 } 1918 (void) vprintf(format, ap); 1919 } 1920 1921 va_end(ap); 1922 1923 need_newline = 0; 1924 } 1925 1926 /* 1927 * This routine is a modified version of printf. It handles the cases 1928 * of silent mode, and only prints the message to the log file, not 1929 * stdout. Other than that is identical to the library version. 1930 */ 1931 /*PRINTFLIKE1*/ 1932 void 1933 log_print(char *format, ...) 1934 { 1935 va_list ap; 1936 1937 va_start(ap, format); 1938 1939 /* 1940 * If we are running silent, skip it. 1941 */ 1942 if (option_s == 0) { 1943 /* 1944 * Do the print to the log file. 1945 */ 1946 if (need_newline) { 1947 (void) fprintf(log_file, "\n"); 1948 } 1949 (void) vfprintf(log_file, format, ap); 1950 (void) fflush(log_file); 1951 } 1952 1953 va_end(ap); 1954 1955 need_newline = 0; 1956 } 1957 1958 /* 1959 * This routine is a modified version of printf. It prints the message 1960 * to stderr, and to the log file is appropriate. 1961 * Other than that is identical to the library version. 1962 */ 1963 /*PRINTFLIKE1*/ 1964 void 1965 err_print(char *format, ...) 1966 { 1967 va_list ap; 1968 1969 va_start(ap, format); 1970 1971 /* 1972 * Flush anything pending to stdout 1973 */ 1974 if (need_newline) { 1975 (void) printf("\n"); 1976 } 1977 (void) fflush(stdout); 1978 /* 1979 * Do the print to stderr. 1980 */ 1981 (void) vfprintf(stderr, format, ap); 1982 /* 1983 * If we are logging, also print to the log file. 1984 */ 1985 if (log_file) { 1986 if (need_newline) { 1987 (void) fprintf(log_file, "\n"); 1988 } 1989 (void) vfprintf(log_file, format, ap); 1990 (void) fflush(log_file); 1991 } 1992 va_end(ap); 1993 1994 need_newline = 0; 1995 } 1996 1997 /* 1998 * Print a number of characters from a buffer. The buffer 1999 * does not need to be null-terminated. Since the data 2000 * may be coming from a device, we cannot be sure the 2001 * data is not crud, so be rather defensive. 2002 */ 2003 void 2004 print_buf(char *buf, int nbytes) 2005 { 2006 int c; 2007 2008 while (nbytes-- > 0) { 2009 c = *buf++; 2010 if (isascii(c) && isprint(c)) { 2011 fmt_print("%c", c); 2012 } else 2013 break; 2014 } 2015 } 2016 2017 #ifdef not 2018 /* 2019 * This routine prints out a message describing the given ctlr. 2020 * The message is identical to the one printed by the kernel during 2021 * booting. 2022 */ 2023 void 2024 pr_ctlrline(struct ctlr_info *ctlr) 2025 { 2026 2027 fmt_print(" %s%d at %s 0x%x ", 2028 ctlr->ctlr_cname, ctlr->ctlr_num, 2029 space2str(ctlr->ctlr_space), ctlr->ctlr_addr); 2030 if (ctlr->ctlr_vec != 0) 2031 fmt_print("vec 0x%x ", ctlr->ctlr_vec); 2032 else 2033 fmt_print("pri %d ", ctlr->ctlr_prio); 2034 fmt_print("\n"); 2035 } 2036 #endif /* not */ 2037 2038 /* 2039 * This routine prints out a message describing the given disk. 2040 * The message is identical to the one printed by the kernel during 2041 * booting. 2042 */ 2043 void 2044 pr_diskline(struct disk_info *disk, int num) 2045 { 2046 struct ctlr_info *ctlr = disk->disk_ctlr; 2047 struct disk_type *type = disk->disk_type; 2048 2049 fmt_print(" %4d. %s ", num, disk->disk_name); 2050 if ((type != NULL) && (disk->label_type == L_TYPE_SOLARIS)) { 2051 fmt_print("<%s cyl %u alt %u hd %u sec %u>", 2052 type->dtype_asciilabel, type->dtype_ncyl, 2053 type->dtype_acyl, type->dtype_nhead, 2054 type->dtype_nsect); 2055 } else if ((type != NULL) && (disk->label_type == L_TYPE_EFI)) { 2056 cur_blksz = disk->disk_lbasize; 2057 print_efi_string(type->vendor, type->product, 2058 type->revision, type->capacity); 2059 } else if (disk->disk_flags & DSK_RESERVED) { 2060 fmt_print("<drive not available: reserved>"); 2061 } else if (disk->disk_flags & DSK_UNAVAILABLE) { 2062 fmt_print("<drive not available>"); 2063 } else { 2064 fmt_print("<drive type unknown>"); 2065 } 2066 if (chk_volname(disk)) { 2067 fmt_print(" "); 2068 print_volname(disk); 2069 } 2070 fmt_print("\n"); 2071 2072 if (disk->devfs_name != NULL) { 2073 fmt_print(" %s\n", disk->devfs_name); 2074 } else { 2075 fmt_print(" %s%d at %s%d slave %d\n", 2076 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit, 2077 ctlr->ctlr_cname, ctlr->ctlr_num, 2078 disk->disk_dkinfo.dki_slave); 2079 } 2080 2081 #ifdef OLD 2082 fmt_print(" %4d. %s at %s%d slave %d", num, disk->disk_name, 2083 ctlr->ctlr_cname, ctlr->ctlr_num, disk->disk_dkinfo.dki_slave); 2084 if (chk_volname(disk)) { 2085 fmt_print(": "); 2086 print_volname(disk); 2087 } 2088 fmt_print("\n"); 2089 if (type != NULL) { 2090 fmt_print(" %s%d: <%s cyl %u alt %u hd %u sec %u>\n", 2091 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit, 2092 type->dtype_asciilabel, type->dtype_ncyl, 2093 type->dtype_acyl, type->dtype_nhead, 2094 type->dtype_nsect); 2095 } else { 2096 fmt_print(" %s%d: <drive type unknown>\n", 2097 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit); 2098 } 2099 #endif /* OLD */ 2100 } 2101 2102 /* 2103 * This routine prints out a given disk block number in cylinder/head/sector 2104 * format. It uses the printing routine passed in to do the actual output. 2105 */ 2106 void 2107 pr_dblock(void (*func)(char *, ...), diskaddr_t bn) 2108 { 2109 if (cur_label == L_TYPE_SOLARIS) { 2110 (*func)("%u/%u/%u", bn2c(bn), 2111 bn2h(bn), bn2s(bn)); 2112 } else { 2113 (*func)("%llu", bn); 2114 } 2115 } 2116 2117 /* 2118 * This routine inputs a character from the data file. It understands 2119 * the use of '\' to prevent interpretation of a newline. It also keeps 2120 * track of the current line in the data file via a global variable. 2121 */ 2122 static int 2123 sup_inputchar(void) 2124 { 2125 int c; 2126 2127 /* 2128 * Input the character. 2129 */ 2130 c = getc(data_file); 2131 /* 2132 * If it's not a backslash, return it. 2133 */ 2134 if (c != '\\') 2135 return (c); 2136 /* 2137 * It was a backslash. Get the next character. 2138 */ 2139 c = getc(data_file); 2140 /* 2141 * If it was a newline, update the line counter and get the next 2142 * character. 2143 */ 2144 if (c == '\n') { 2145 data_lineno++; 2146 c = getc(data_file); 2147 } 2148 /* 2149 * Return the character. 2150 */ 2151 return (c); 2152 } 2153 2154 /* 2155 * This routine pushes a character back onto the input pipe for the data file. 2156 */ 2157 static void 2158 sup_pushchar(int c) 2159 { 2160 (void) ungetc(c, data_file); 2161 } 2162 2163 /* 2164 * Variables to support pushing back tokens 2165 */ 2166 static int have_pushed_token = 0; 2167 static TOKEN pushed_buf; 2168 static int pushed_token; 2169 2170 /* 2171 * This routine inputs a token from the data file. A token is a series 2172 * of contiguous non-white characters or a recognized special delimiter 2173 * character. Use of the wrapper lets us always have the value of the 2174 * last token around, which is useful for error recovery. 2175 */ 2176 int 2177 sup_gettoken(char *buf) 2178 { 2179 last_token_type = sup_get_token(buf); 2180 return (last_token_type); 2181 } 2182 2183 static int 2184 sup_get_token(char *buf) 2185 { 2186 char *ptr = buf; 2187 int c, quoted = 0; 2188 2189 /* 2190 * First check for presence of push-backed token. 2191 * If so, return it. 2192 */ 2193 if (have_pushed_token) { 2194 have_pushed_token = 0; 2195 bcopy(pushed_buf, buf, TOKEN_SIZE+1); 2196 return (pushed_token); 2197 } 2198 /* 2199 * Zero out the returned token buffer 2200 */ 2201 bzero(buf, TOKEN_SIZE + 1); 2202 /* 2203 * Strip off leading white-space. 2204 */ 2205 while ((isspace(c = sup_inputchar())) && (c != '\n')) 2206 ; 2207 /* 2208 * Read in characters until we hit unquoted white-space. 2209 */ 2210 for (; !isspace(c) || quoted; c = sup_inputchar()) { 2211 /* 2212 * If we hit eof, that's a token. 2213 */ 2214 if (feof(data_file)) 2215 return (SUP_EOF); 2216 /* 2217 * If we hit a double quote, change the state of quoting. 2218 */ 2219 if (c == '"') { 2220 quoted = !quoted; 2221 continue; 2222 } 2223 /* 2224 * If we hit a newline, that delimits a token. 2225 */ 2226 if (c == '\n') 2227 break; 2228 /* 2229 * If we hit any nonquoted special delimiters, that delimits 2230 * a token. 2231 */ 2232 if (!quoted && (c == '=' || c == ',' || c == ':' || 2233 c == '#' || c == '|' || c == '&' || c == '~')) 2234 break; 2235 /* 2236 * Store the character if there's room left. 2237 */ 2238 if (ptr - buf < TOKEN_SIZE) 2239 *ptr++ = (char)c; 2240 } 2241 /* 2242 * If we stored characters in the buffer, then we inputted a string. 2243 * Push the delimiter back into the pipe and return the string. 2244 */ 2245 if (ptr - buf > 0) { 2246 sup_pushchar(c); 2247 return (SUP_STRING); 2248 } 2249 /* 2250 * We didn't input a string, so we must have inputted a known delimiter. 2251 * store the delimiter in the buffer, so it will get returned. 2252 */ 2253 buf[0] = c; 2254 /* 2255 * Switch on the delimiter. Return the appropriate value for each one. 2256 */ 2257 switch (c) { 2258 case '=': 2259 return (SUP_EQL); 2260 case ':': 2261 return (SUP_COLON); 2262 case ',': 2263 return (SUP_COMMA); 2264 case '\n': 2265 return (SUP_EOL); 2266 case '|': 2267 return (SUP_OR); 2268 case '&': 2269 return (SUP_AND); 2270 case '~': 2271 return (SUP_TILDE); 2272 case '#': 2273 /* 2274 * For comments, we flush out the rest of the line and return 2275 * an EOL. 2276 */ 2277 while ((c = sup_inputchar()) != '\n' && !feof(data_file)) 2278 ; 2279 if (feof(data_file)) 2280 return (SUP_EOF); 2281 else 2282 return (SUP_EOL); 2283 /* 2284 * Shouldn't ever get here. 2285 */ 2286 default: 2287 return (SUP_STRING); 2288 } 2289 } 2290 2291 /* 2292 * Push back a token 2293 */ 2294 void 2295 sup_pushtoken(char *token_buf, int token_type) 2296 { 2297 /* 2298 * We can only push one token back at a time 2299 */ 2300 assert(have_pushed_token == 0); 2301 2302 have_pushed_token = 1; 2303 bcopy(token_buf, pushed_buf, TOKEN_SIZE+1); 2304 pushed_token = token_type; 2305 } 2306 2307 /* 2308 * Get an entire line of input. Handles logging, comments, 2309 * and EOF. 2310 */ 2311 void 2312 get_inputline(char *line, int nbytes) 2313 { 2314 char *p = line; 2315 int c; 2316 2317 /* 2318 * Remove any leading white-space and comments 2319 */ 2320 do { 2321 while ((isspace(c = getchar())) && (c != '\n')) 2322 ; 2323 } while (c == COMMENT_CHAR); 2324 /* 2325 * Loop on each character until end of line 2326 */ 2327 while (c != '\n') { 2328 /* 2329 * If we hit eof, get out. 2330 */ 2331 if (checkeof()) { 2332 fullabort(); 2333 } 2334 /* 2335 * Add the character to the buffer. 2336 */ 2337 if (nbytes > 1) { 2338 *p++ = (char)c; 2339 nbytes --; 2340 } 2341 /* 2342 * Get the next character. 2343 */ 2344 c = getchar(); 2345 } 2346 /* 2347 * Null terminate the token. 2348 */ 2349 *p = 0; 2350 /* 2351 * Indicate that we've emptied the pipe 2352 */ 2353 token_present = 0; 2354 /* 2355 * If we're running out of a file, echo the line to 2356 * the user, otherwise if we're logging, copy the 2357 * input to the log file. 2358 */ 2359 if (option_f) { 2360 fmt_print("%s\n", line); 2361 } else if (log_file) { 2362 log_print("%s\n", line); 2363 } 2364 } 2365 2366 /* 2367 * execute the shell escape command 2368 */ 2369 int 2370 execute_shell(char *s, size_t buff_size) 2371 { 2372 struct termio termio; 2373 struct termios tty; 2374 int tty_flag, i, j; 2375 char *shell_name; 2376 static char *default_shell = "/bin/sh"; 2377 2378 tty_flag = -1; 2379 2380 if (*s == '\0') { 2381 shell_name = getenv("SHELL"); 2382 2383 if (shell_name == NULL) { 2384 shell_name = default_shell; 2385 } 2386 if (strlcpy(s, shell_name, buff_size) >= 2387 buff_size) { 2388 err_print("Error: Shell command ($SHELL) too long.\n"); 2389 fullabort(); 2390 } 2391 } 2392 2393 /* save tty information */ 2394 2395 if (isatty(0)) { 2396 if (ioctl(0, TCGETS, &tty) == 0) 2397 tty_flag = 1; 2398 else { 2399 if (ioctl(0, TCGETA, &termio) == 0) { 2400 tty_flag = 0; 2401 tty.c_iflag = termio.c_iflag; 2402 tty.c_oflag = termio.c_oflag; 2403 tty.c_cflag = termio.c_cflag; 2404 tty.c_lflag = termio.c_lflag; 2405 for (i = 0; i < NCC; i++) 2406 tty.c_cc[i] = termio.c_cc[i]; 2407 } 2408 } 2409 } 2410 2411 /* close the current file descriptor */ 2412 if (cur_disk != NULL) { 2413 (void) close(cur_file); 2414 } 2415 2416 /* execute the shell escape */ 2417 (void) system(s); 2418 2419 /* reopen file descriptor if one was open before */ 2420 if (cur_disk != NULL) { 2421 if ((cur_file = open_disk(cur_disk->disk_path, 2422 O_RDWR | O_NDELAY)) < 0) { 2423 err_print("Error: can't reopen selected disk '%s'. \n", 2424 cur_disk->disk_name); 2425 fullabort(); 2426 } 2427 } 2428 2429 /* Restore tty information */ 2430 2431 if (isatty(0)) { 2432 if (tty_flag > 0) 2433 (void) ioctl(0, TCSETSW, &tty); 2434 else if (tty_flag == 0) { 2435 termio.c_iflag = tty.c_iflag; 2436 termio.c_oflag = tty.c_oflag; 2437 termio.c_cflag = tty.c_cflag; 2438 termio.c_lflag = tty.c_lflag; 2439 for (j = 0; j < NCC; j++) 2440 termio.c_cc[j] = tty.c_cc[j]; 2441 (void) ioctl(0, TCSETAW, &termio); 2442 } 2443 2444 if (isatty(1)) { 2445 fmt_print("\n[Hit Return to continue] \n"); 2446 (void) fflush(stdin); 2447 if (getchar() == EOF) 2448 fullabort(); 2449 } 2450 } 2451 return (0); 2452 } 2453 2454 void 2455 print_efi_string(char *vendor, char *product, char *revision, 2456 uint64_t capacity) 2457 { 2458 char *new_vendor; 2459 char *new_product; 2460 char *new_revision; 2461 char capacity_string[10]; 2462 float scaled; 2463 int i; 2464 2465 /* Strip whitespace from the end of inquiry strings */ 2466 new_vendor = strdup(vendor); 2467 if (new_vendor == NULL) 2468 return; 2469 2470 for (i = (strlen(new_vendor) - 1); i >= 0; i--) { 2471 if (new_vendor[i] != 0x20) { 2472 new_vendor[i+1] = '\0'; 2473 break; 2474 } 2475 } 2476 2477 new_product = strdup(product); 2478 if (new_product == NULL) { 2479 free(new_vendor); 2480 return; 2481 } 2482 2483 for (i = (strlen(new_product) - 1); i >= 0; i--) { 2484 if (new_product[i] != 0x20) { 2485 new_product[i+1] = '\0'; 2486 break; 2487 } 2488 } 2489 2490 new_revision = strdup(revision); 2491 if (new_product == NULL) { 2492 free(new_vendor); 2493 free(new_product); 2494 return; 2495 } 2496 2497 for (i = (strlen(new_revision) - 1); i >= 0; i--) { 2498 if (new_revision[i] != 0x20) { 2499 new_revision[i+1] = '\0'; 2500 break; 2501 } 2502 } 2503 2504 /* Now build size string */ 2505 scaled = bn2mb(capacity); 2506 if (scaled >= (float)1024.0 * 1024) { 2507 (void) snprintf(capacity_string, sizeof (capacity_string), 2508 "%.2fTB", scaled/((float)1024.0 * 1024)); 2509 } else if (scaled >= (float)1024.0) { 2510 (void) snprintf(capacity_string, sizeof (capacity_string), 2511 "%.2fGB", scaled/(float)1024.0); 2512 } else { 2513 (void) snprintf(capacity_string, sizeof (capacity_string), 2514 "%.2fMB", scaled); 2515 } 2516 2517 fmt_print("<%s-%s-%s-%s>", 2518 new_vendor, new_product, new_revision, capacity_string); 2519 2520 free(new_revision); 2521 free(new_product); 2522 free(new_vendor); 2523 } 2524