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