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