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