Merge branch 'cleanups'
[unleashed.git] / usr / src / cmd / format / io.c
blobb22d422a3a601461e9624fa4ad5232abb804c805
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
28 * This file contains I/O related functions.
30 #include "global.h"
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>
42 #include "startup.h"
43 #include "misc.h"
44 #include "menu_partition.h"
45 #include "param.h"
46 #include "menu.h"
49 extern int data_lineno;
50 extern char *space2str();
51 extern long strtol();
54 * This variable is used to determine whether a token is present in the pipe
55 * already.
57 static char token_present = 0;
60 * This variable always gives us access to the most recent token type
62 int last_token_type = 0;
64 #ifdef __STDC__
66 * Prototypes for ANSI C compilers
68 static int sup_get_token(char *);
69 static void pushchar(int c);
70 static int checkeof(void);
71 static void flushline(void);
72 static int strcnt(char *s1, char *s2);
73 static int getbn(char *str, diskaddr_t *iptr);
74 static void print_input_choices(int type, u_ioparam_t *param);
75 static int slist_widest_str(slist_t *slist);
76 static void ljust_print(char *str, int width);
77 static int sup_inputchar(void);
78 static void sup_pushchar(int c);
79 static int geti64(char *str, uint64_t *iptr, uint64_t *wild);
81 #else /* __STDC__ */
83 * Prototypes for non-ANSI C compilers
86 static int sup_get_token();
87 static void pushchar(int c);
88 static int checkeof(void);
89 static void flushline(void);
90 static int strcnt(char *s1, char *s2);
91 static int getbn(char *str, diskaddr_t *iptr);
92 static void print_input_choices(int type, u_ioparam_t *param);
93 static int slist_widest_str(slist_t *slist);
94 static void ljust_print(char *str, int width);
95 static int sup_inputchar(void);
96 static void sup_pushchar(int c);
97 static int geti64(char *str, uint64_t *iptr, uint64_t *wild);
99 #endif /* __STDC__ */
103 * This routine pushes the given character back onto the input stream.
105 static void
106 pushchar(c)
107 int c;
109 (void) ungetc(c, stdin);
113 * This routine checks the input stream for an eof condition.
115 static int
116 checkeof()
118 return (feof(stdin));
122 * This routine gets the next token off the input stream. A token is
123 * basically any consecutive non-white characters.
125 char *
126 gettoken(inbuf)
127 char *inbuf;
129 char *ptr = inbuf;
130 int c, quoted = 0;
132 retoke:
134 * Remove any leading white-space.
136 while ((isspace(c = getchar())) && (c != '\n'))
139 * If we are at the beginning of a line and hit the comment character,
140 * flush the line and start again.
142 if (!token_present && c == COMMENT_CHAR) {
143 token_present = 1;
144 flushline();
145 goto retoke;
148 * Loop on each character until we hit unquoted white-space.
150 while (!isspace(c) || quoted && (c != '\n')) {
152 * If we hit eof, get out.
154 if (checkeof())
155 return (NULL);
157 * If we hit a double quote, change the state of quotedness.
159 if (c == '"')
160 quoted = !quoted;
162 * If there's room in the buffer, add the character to the end.
164 else if (ptr - inbuf < TOKEN_SIZE)
165 *ptr++ = (char)c;
167 * Get the next character.
169 c = getchar();
172 * Null terminate the token.
174 *ptr = '\0';
176 * Peel off white-space still in the pipe.
178 while (isspace(c) && (c != '\n'))
179 c = getchar();
181 * If we hit another token, push it back and set state.
183 if (c != '\n') {
184 pushchar(c);
185 token_present = 1;
186 } else
187 token_present = 0;
189 * Return the token.
191 return (inbuf);
195 * This routine removes the leading and trailing spaces from a token.
197 void
198 clean_token(cleantoken, token)
199 char *cleantoken, *token;
201 char *ptr;
204 * Strip off leading white-space.
206 for (ptr = token; isspace(*ptr); ptr++)
209 * Copy it into the clean buffer.
211 (void) strcpy(cleantoken, ptr);
213 * Strip off trailing white-space.
215 for (ptr = cleantoken + strlen(cleantoken) - 1;
216 isspace(*ptr) && (ptr >= cleantoken); ptr--) {
217 *ptr = '\0';
222 * This routine checks if a token is already present on the input line
225 istokenpresent()
227 return (token_present);
231 * This routine flushes the rest of an input line if there is known
232 * to be data in it. The flush has to be qualified because the newline
233 * may have already been swallowed by the last gettoken.
235 static void
236 flushline()
238 if (token_present) {
240 * Flush the pipe to eol or eof.
242 while ((getchar() != '\n') && !checkeof())
245 * Mark the pipe empty.
247 token_present = 0;
252 * This routine returns the number of characters that are identical
253 * between s1 and s2, stopping as soon as a mismatch is found.
255 static int
256 strcnt(s1, s2)
257 char *s1, *s2;
259 int i = 0;
261 while ((*s1 != '\0') && (*s1++ == *s2++))
262 i++;
263 return (i);
267 * This routine converts the given token into an integer. The token
268 * must convert cleanly into an integer with no unknown characters.
269 * If the token is the wildcard string, and the wildcard parameter
270 * is present, the wildcard value will be returned.
273 geti(str, iptr, wild)
274 char *str;
275 int *iptr, *wild;
277 char *str2;
280 * If there's a wildcard value and the string is wild, return the
281 * wildcard value.
283 if (wild != NULL && strcmp(str, WILD_STRING) == 0)
284 *iptr = *wild;
285 else {
287 * Conver the string to an integer.
289 *iptr = (int)strtol(str, &str2, 0);
291 * If any characters didn't convert, it's an error.
293 if (*str2 != '\0') {
294 err_print("`%s' is not an integer.\n", str);
295 return (-1);
298 return (0);
302 * This routine converts the given token into a long long. The token
303 * must convert cleanly into a 64-bit integer with no unknown characters.
304 * If the token is the wildcard string, and the wildcard parameter
305 * is present, the wildcard value will be returned.
307 static int
308 geti64(str, iptr, wild)
309 char *str;
310 uint64_t *iptr, *wild;
312 char *str2;
315 * If there's a wildcard value and the string is wild, return the
316 * wildcard value.
318 if ((wild != NULL) && (strcmp(str, WILD_STRING)) == 0) {
319 *iptr = *wild;
320 } else {
322 * Conver the string to an integer.
324 *iptr = (uint64_t)strtoll(str, &str2, 0);
326 * If any characters didn't convert, it's an error.
328 if (*str2 != '\0') {
329 err_print("`%s' is not an integer.\n", str);
330 return (-1);
333 return (0);
337 * This routine converts the given string into a block number on the
338 * current disk. The format of a block number is either a self-based
339 * number, or a series of self-based numbers separated by slashes.
340 * Any number preceeding the first slash is considered a cylinder value.
341 * Any number succeeding the first slash but preceeding the second is
342 * considered a head value. Any number succeeding the second slash is
343 * considered a sector value. Any of these numbers can be wildcarded
344 * to the highest possible legal value.
346 static int
347 getbn(str, iptr)
348 char *str;
349 diskaddr_t *iptr;
351 char *cptr, *hptr, *sptr;
352 int cyl, head, sect;
353 int wild;
354 diskaddr_t wild64;
355 TOKEN buf;
358 * Set cylinder pointer to beginning of string.
360 cptr = str;
362 * Look for the first slash.
364 while ((*str != '\0') && (*str != '/'))
365 str++;
367 * If there wasn't one, convert string to an integer and return it.
369 if (*str == '\0') {
370 wild64 = physsects() - 1;
371 if (geti64(cptr, iptr, &wild64))
372 return (-1);
373 return (0);
376 * Null out the slash and set head pointer just beyond it.
378 *str++ = '\0';
379 hptr = str;
381 * Look for the second slash.
383 while ((*str != '\0') && (*str != '/'))
384 str++;
386 * If there wasn't one, sector pointer points to a .
388 if (*str == '\0')
389 sptr = str;
391 * If there was, null it out and set sector point just beyond it.
393 else {
394 *str++ = '\0';
395 sptr = str;
398 * Convert the cylinder part to an integer and store it.
400 clean_token(buf, cptr);
401 wild = ncyl + acyl - 1;
402 if (geti(buf, &cyl, &wild))
403 return (-1);
404 if ((cyl < 0) || (cyl >= (ncyl + acyl))) {
405 err_print("`%d' is out of range.\n", cyl);
406 return (-1);
409 * Convert the head part to an integer and store it.
411 clean_token(buf, hptr);
412 wild = nhead - 1;
413 if (geti(buf, &head, &wild))
414 return (-1);
415 if ((head < 0) || (head >= nhead)) {
416 err_print("`%d' is out of range.\n", head);
417 return (-1);
420 * Convert the sector part to an integer and store it.
422 clean_token(buf, sptr);
423 wild = sectors(head) - 1;
424 if (geti(buf, &sect, &wild))
425 return (-1);
426 if ((sect < 0) || (sect >= sectors(head))) {
427 err_print("`%d' is out of range.\n", sect);
428 return (-1);
431 * Combine the pieces into a block number and return it.
433 *iptr = chs2bn(cyl, head, sect);
434 return (0);
438 * This routine is the basis for all input into the program. It
439 * understands the semantics of a set of input types, and provides
440 * consistent error messages for all input. It allows for default
441 * values and prompt strings.
443 uint64_t
444 input(type, promptstr, delim, param, deflt, cmdflag)
445 int type;
446 char *promptstr;
447 int delim;
448 u_ioparam_t *param;
449 int *deflt;
450 int cmdflag;
452 int interactive, help, i, length, index, tied;
453 blkaddr_t bn;
454 diskaddr_t bn64;
455 char **str, **strings;
456 TOKEN token, cleantoken;
457 TOKEN token2, cleantoken2;
458 char *arg;
459 struct bounds *bounds;
460 char *s;
461 int value;
462 int cyls, cylno;
463 uint64_t blokno;
464 float nmegs;
465 float ngigs;
466 char shell_argv[MAXPATHLEN];
467 part_deflt_t *part_deflt;
468 efi_deflt_t *efi_deflt;
471 * Optional integer input has been added as a hack.
472 * Function result is 1 if user typed anything.
473 * Whatever they typed is returned in *deflt.
474 * This permits us to distinguish between "no value",
475 * and actually entering in some value, for instance.
477 if (type == FIO_OPINT) {
478 assert(deflt != NULL);
480 reprompt:
481 help = interactive = 0;
483 * If we are inputting a command, flush any current input in the pipe.
485 if (cmdflag == CMD_INPUT)
486 flushline();
488 * Note whether the token is already present.
490 if (!token_present)
491 interactive = 1;
493 * Print the prompt.
495 fmt_print(promptstr);
497 * If there is a default value, print it in a format appropriate
498 * for the input type.
500 if (deflt != NULL) {
501 switch (type) {
502 case FIO_BN:
503 fmt_print("[%llu, ", *(diskaddr_t *)deflt);
504 pr_dblock(fmt_print, *(diskaddr_t *)deflt);
505 fmt_print("]");
506 break;
507 case FIO_INT:
508 fmt_print("[%d]", *deflt);
509 break;
510 case FIO_INT64:
511 efi_deflt = (efi_deflt_t *)deflt;
512 fmt_print("[%llu]", efi_deflt->start_sector);
513 break;
514 case FIO_CSTR:
515 case FIO_MSTR:
516 strings = (char **)param->io_charlist;
517 for (i = 0, str = strings; i < *deflt; i++, str++)
519 fmt_print("[%s]", *str);
520 break;
521 case FIO_OSTR:
522 fmt_print("[\"%s\"]", (char *)deflt);
523 break;
524 case FIO_SLIST:
526 * Search for a string matching the default
527 * value. If found, use it. Otherwise
528 * assume the default value is actually
529 * an illegal choice, and default to
530 * the first item in the list.
532 s = find_string(param->io_slist, *deflt);
533 if (s == NULL) {
534 s = (param->io_slist)->str;
536 fmt_print("[%s]", s);
537 break;
538 case FIO_CYL:
540 * Old-style partition size input, used to
541 * modify complete partition tables
543 blokno = *(blkaddr32_t *)deflt;
544 fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno,
545 bn2c(blokno), bn2mb(blokno), bn2gb(blokno));
546 break;
547 case FIO_ECYL:
549 * set up pointer to partition defaults
550 * structure
552 part_deflt = (part_deflt_t *)deflt;
555 * Build print format specifier. We use the
556 * starting cylinder number which was entered
557 * before this call to input(), in case the
558 * user has changed it from the value in the
559 * cur_parts->pinfo_map[].dkl_cylno
560 * field for the current parition
564 * Determine the proper default end cylinder:
565 * Start Cyl Default Size End Cylinder
566 * 0 0 0
567 * >0 0 Start Cyl
568 * 0 >0 Default Size
569 * (Cyls) - 1
570 * >0 >0 (Start +
571 * Default Size
572 * (Cyls)) -1
575 if (part_deflt->deflt_size == 0) {
576 cylno = part_deflt->start_cyl;
577 } else if (part_deflt->start_cyl == 0) {
578 cylno = bn2c(part_deflt->deflt_size) - 1;
579 } else {
580 cylno = (bn2c(part_deflt->deflt_size) +
581 part_deflt->start_cyl) - 1;
584 fmt_print("[%ub, %uc, %de, %1.2fmb, %1.2fgb]",
585 part_deflt->deflt_size,
586 bn2c(part_deflt->deflt_size),
587 cylno,
588 bn2mb(part_deflt->deflt_size),
589 bn2gb(part_deflt->deflt_size));
591 break;
592 case FIO_EFI:
593 efi_deflt = (efi_deflt_t *)deflt;
595 fmt_print("[%llub, %llue, %llumb, %llugb, %llutb]",
596 efi_deflt->end_sector,
597 efi_deflt->start_sector + efi_deflt->end_sector - 1,
598 (efi_deflt->end_sector * cur_blksz) /
599 (1024 * 1024),
600 (efi_deflt->end_sector * cur_blksz) /
601 (1024 * 1024 * 1024),
602 (efi_deflt->end_sector * cur_blksz) /
603 ((uint64_t)1024 * 1024 * 1024 * 1024));
604 break;
605 case FIO_OPINT:
606 /* no default value for optional input type */
607 fmt_print("[default]");
608 break;
609 default:
610 err_print("Error: unknown input type.\n");
611 fullabort();
615 * Print the delimiter character.
617 fmt_print("%c ", delim);
619 * Get the token. If we hit eof, exit the program gracefully.
621 if (gettoken(token) == NULL)
622 fullabort();
625 * check if the user has issued (!) , escape to shell
627 if ((cmdflag == CMD_INPUT) && (token[0] == '!')) {
629 /* get the list of arguments to shell command */
630 (void) memset(shell_argv, 0, sizeof (shell_argv));
632 /* initialize to the first token... */
633 arg = &token[1];
636 * ... and then collect all tokens until the end of
637 * the line as arguments
639 do {
640 /* skip empty tokens. */
641 if (*arg == '\0')
642 continue;
644 * If either of the following two strlcat()
645 * operations overflows, report an error and
646 * exit gracefully.
648 if ((strlcat(shell_argv, arg, sizeof (shell_argv)) >=
649 sizeof (shell_argv)) ||
650 (strlcat(shell_argv, " ", sizeof (shell_argv)) >=
651 sizeof (shell_argv))) {
652 err_print("Error: Command line too long.\n");
653 fullabort();
655 } while (token_present && (arg = gettoken(token)) != NULL);
657 /* execute the shell command */
658 (void) execute_shell(shell_argv, sizeof (shell_argv));
659 redisplay_menu_list((char **)param->io_charlist);
660 if (interactive) {
661 goto reprompt;
666 * Certain commands accept up to two tokens
667 * Unfortunately, this is kind of a hack.
669 token2[0] = 0;
670 cleantoken2[0] = 0;
671 if (type == FIO_CYL || type == FIO_ECYL) {
672 if (token_present) {
673 if (gettoken(token2) == NULL)
674 fullabort();
675 clean_token(cleantoken2, token2);
679 * Echo the token back to the user if it was in the pipe or we
680 * are running out of a command file.
682 if (!interactive || option_f) {
683 if (token2[0] == 0) {
684 fmt_print("%s\n", token);
685 } else {
686 fmt_print("%s %s\n", token, token2);
690 * If we are logging, echo the token to the log file. The else
691 * is necessary here because the above printf will also put the
692 * token in the log file.
694 else if (log_file) {
695 log_print("%s %s\n", token, token2);
698 * If the token was not in the pipe and it wasn't a command, flush
699 * the rest of the line to keep things in sync.
701 if (interactive && cmdflag != CMD_INPUT)
702 flushline();
704 * Scrub off the white-space.
706 clean_token(cleantoken, token);
708 * If the input was a blank line and we weren't prompting
709 * specifically for a blank line...
711 if ((strcmp(cleantoken, "") == 0) && (type != FIO_BLNK)) {
713 * If there's a default, return it.
715 if (deflt != NULL) {
716 if (type == FIO_OSTR) {
718 * Duplicate and return the default string
720 return ((int)alloc_string((char *)deflt));
721 } else if (type == FIO_SLIST) {
723 * If we can find a match for the default
724 * value in the list, return the default
725 * value. If there's no match for the
726 * default value, it's an illegal
727 * choice. Return the first value in
728 * the list.
730 s = find_string(param->io_slist, *deflt);
731 if ((cur_label == L_TYPE_EFI) &&
732 (s == NULL)) {
733 return (*deflt);
735 if (s == NULL) {
736 return ((param->io_slist)->value);
737 } else {
738 return (*deflt);
740 } else if (type == FIO_OPINT) {
742 * The user didn't enter anything
744 return (0);
745 } else if (type == FIO_ECYL) {
746 return (part_deflt->deflt_size);
747 } else if (type == FIO_INT64) {
748 return (efi_deflt->start_sector);
749 } else if (type == FIO_EFI) {
750 return (efi_deflt->end_sector);
751 } else {
752 return (*deflt);
756 * If the blank was not in the pipe, just reprompt.
758 if (interactive) {
759 goto reprompt;
762 * If the blank was in the pipe, it's an error.
764 err_print("No default for this entry.\n");
765 cmdabort(SIGINT);
768 * If token is a '?' or a 'h', it is a request for help.
770 if ((strcmp(cleantoken, "?") == 0) ||
771 (strcmp(cleantoken, "h") == 0) ||
772 (strcmp(cleantoken, "help") == 0)) {
773 help = 1;
776 * Switch on the type of input expected.
778 switch (type) {
780 * Expecting a disk block number.
782 case FIO_BN:
784 * Parameter is the bounds of legal block numbers.
786 bounds = (struct bounds *)&param->io_bounds;
788 * Print help message if required.
790 if (help) {
791 fmt_print("Expecting a block number from %llu (",
792 bounds->lower);
793 pr_dblock(fmt_print, bounds->lower);
794 fmt_print(") to %llu (", bounds->upper);
795 pr_dblock(fmt_print, bounds->upper);
796 fmt_print(")\n");
797 break;
800 * Convert token to a disk block number.
802 if (cur_label == L_TYPE_EFI) {
803 if (geti64(cleantoken, (uint64_t *)&bn64,
804 (uint64_t *)NULL))
805 break;
806 } else {
807 if (getbn(cleantoken, &bn64))
808 break;
811 * Check to be sure it is within the legal bounds.
813 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
814 err_print("`");
815 pr_dblock(err_print, bn64);
816 err_print("' is out of range.\n");
817 break;
820 * It's ok, return it.
822 return (bn64);
824 * Expecting an integer.
826 case FIO_INT:
828 * Parameter is the bounds of legal integers.
830 bounds = (struct bounds *)&param->io_bounds;
832 * Print help message if required.
834 if (help) {
835 fmt_print("Expecting an integer from %llu",
836 bounds->lower);
837 fmt_print(" to %llu\n", bounds->upper);
838 break;
841 * Convert the token into an integer.
843 if (geti(cleantoken, (int *)&bn, NULL))
844 break;
846 * Check to be sure it is within the legal bounds.
848 if ((bn < bounds->lower) || (bn > bounds->upper)) {
849 err_print("`%lu' is out of range.\n", bn);
850 break;
853 * If it's ok, return it.
855 return (bn);
856 case FIO_INT64:
858 * Parameter is the bounds of legal integers.
860 bounds = (struct bounds *)&param->io_bounds;
862 * Print help message if required.
864 if (help) {
865 fmt_print("Expecting an integer from %llu",
866 bounds->lower);
867 fmt_print(" to %llu\n", bounds->upper);
868 break;
871 * Convert the token into an integer.
873 if (geti64(cleantoken, (uint64_t *)&bn64, (uint64_t *)NULL)) {
874 break;
877 * Check to be sure it is within the legal bounds.
879 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
880 err_print("`%llu' is out of range.\n", bn64);
881 break;
884 * If it's ok, return it.
886 return (bn64);
888 * Expecting an integer, or no input.
890 case FIO_OPINT:
892 * Parameter is the bounds of legal integers.
894 bounds = (struct bounds *)&param->io_bounds;
896 * Print help message if required.
898 if (help) {
899 fmt_print("Expecting an integer from %llu",
900 bounds->lower);
901 fmt_print(" to %llu, or no input\n", bounds->upper);
902 break;
905 * Convert the token into an integer.
907 if (geti(cleantoken, (int *)&bn, NULL))
908 break;
910 * Check to be sure it is within the legal bounds.
912 if ((bn < bounds->lower) || (bn > bounds->upper)) {
913 err_print("`%lu' is out of range.\n", bn);
914 break;
917 * For optional case, return 1 indicating that
918 * the user actually did enter something.
920 if (!deflt)
921 *deflt = bn;
922 return (1);
924 * Expecting a closed string. This means that the input
925 * string must exactly match one of the strings passed in
926 * as the parameter.
928 case FIO_CSTR:
930 * The parameter is a null terminated array of character
931 * pointers, each one pointing to a legal input string.
933 strings = (char **)param->io_charlist;
935 * Walk through the legal strings, seeing if any of them
936 * match the token. If a match is made, return the index
937 * of the string that was matched.
939 for (str = strings; *str != NULL; str++)
940 if (strcmp(cleantoken, *str) == 0)
941 return (str - strings);
943 * Print help message if required.
945 if (help) {
946 print_input_choices(type, param);
947 } else {
948 err_print("`%s' is not expected.\n", cleantoken);
950 break;
952 * Expecting a matched string. This means that the input
953 * string must either match one of the strings passed in,
954 * or be a unique abbreviation of one of them.
956 case FIO_MSTR:
958 * The parameter is a null terminated array of character
959 * pointers, each one pointing to a legal input string.
961 strings = (char **)param->io_charlist;
962 length = index = tied = 0;
964 * Loop through the legal input strings.
966 for (str = strings; *str != NULL; str++) {
968 * See how many characters of the token match
969 * this legal string.
971 i = strcnt(cleantoken, *str);
973 * If it's not the whole token, then it's not a match.
975 if ((uint_t)i < strlen(cleantoken))
976 continue;
978 * If it ties with another input, remember that.
980 if (i == length)
981 tied = 1;
983 * If it matches the most so far, record that.
985 if (i > length) {
986 index = str - strings;
987 tied = 0;
988 length = i;
992 * Print help message if required.
994 if (length == 0) {
995 if (help) {
996 print_input_choices(type, param);
997 } else {
998 err_print("`%s' is not expected.\n",
999 cleantoken);
1001 break;
1004 * If the abbreviation was non-unique, it's an error.
1006 if (tied) {
1007 err_print("`%s' is ambiguous.\n", cleantoken);
1008 break;
1011 * We matched one. Return the index of the string we matched.
1013 return (index);
1015 * Expecting an open string. This means that any string is legal.
1017 case FIO_OSTR:
1019 * Print a help message if required.
1021 if (help) {
1022 fmt_print("Expecting a string\n");
1023 break;
1026 * alloc a copy of the string and return it
1028 return ((int)alloc_string(token));
1031 * Expecting a blank line.
1033 case FIO_BLNK:
1035 * We are always in non-echo mode when we are inputting
1036 * this type. We echo the newline as a carriage return
1037 * only so the prompt string will be covered over.
1039 nolog_print("\015");
1041 * If we are logging, send a newline to the log file.
1043 if (log_file)
1044 log_print("\n");
1046 * There is no value returned for this type.
1048 return (0);
1051 * Expecting one of the entries in a string list.
1052 * Accept unique abbreviations.
1053 * Return the value associated with the matched string.
1055 case FIO_SLIST:
1056 i = find_value((slist_t *)param->io_slist,
1057 cleantoken, &value);
1058 if (i == 1) {
1059 return (value);
1060 } else {
1062 * Print help message if required.
1065 if (help) {
1066 print_input_choices(type, param);
1067 } else {
1068 if (i == 0)
1069 err_print("`%s' not expected.\n",
1070 cleantoken);
1071 else
1072 err_print("`%s' is ambiguous.\n",
1073 cleantoken);
1076 break;
1079 * Cylinder size input when modifying a complete partition map
1081 case FIO_CYL:
1083 * Parameter is the bounds of legal block numbers.
1085 bounds = (struct bounds *)&param->io_bounds;
1086 assert(bounds->lower == 0);
1088 * Print help message if required.
1090 if (help) {
1091 fmt_print("Expecting up to %llu blocks,",
1092 bounds->upper);
1093 fmt_print(" %u cylinders, ", bn2c(bounds->upper));
1094 fmt_print(" %1.2f megabytes, ", bn2mb(bounds->upper));
1095 fmt_print("or %1.2f gigabytes\n", bn2gb(bounds->upper));
1096 break;
1099 * Parse the first token: try to find 'b', 'c' or 'm'
1101 s = cleantoken;
1102 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
1103 s++;
1106 * If we found a conversion specifier, second token is unused
1107 * Otherwise, the second token should supply it.
1109 if (*s != 0) {
1110 value = *s;
1111 *s = 0;
1112 } else {
1113 value = cleantoken2[0];
1116 * If the token is the wild card, simply supply the max
1117 * This order allows the user to specify the maximum in
1118 * either blocks/cyls/megabytes - a convenient fiction.
1120 if (strcmp(cleantoken, WILD_STRING) == 0) {
1121 return (bounds->upper);
1124 * Allow the user to specify zero with no units,
1125 * by just defaulting to cylinders.
1127 if (strcmp(cleantoken, "0") == 0) {
1128 value = 'c';
1131 * If there's a decimal point, but no unit specification,
1132 * let's assume megabytes.
1134 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
1135 value = 'm';
1138 * Handle each unit type we support
1140 switch (value) {
1141 case 'b':
1143 * Convert token to a disk block number.
1145 if (geti64(cleantoken, &bn64, &bounds->upper))
1146 break;
1148 * Check to be sure it is within the legal bounds.
1150 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
1151 err_print(
1152 "`%llub' is out of the range %llu "
1153 "to %llu\n",
1154 bn64, bounds->lower, bounds->upper);
1155 break;
1158 * Verify the block lies on a cylinder boundary
1160 if ((bn64 % spc()) != 0) {
1161 err_print(
1162 "partition size must be a multiple of "
1163 "%u blocks to lie on a cylinder boundary\n",
1164 spc());
1165 err_print(
1166 "%llu blocks is approximately %u cylinders,"
1167 " %1.2f megabytes or %1.2f gigabytes\n",
1168 bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
1169 break;
1171 return (bn64);
1172 case 'c':
1174 * Convert token from a number of cylinders to
1175 * a number of blocks.
1177 i = bn2c(bounds->upper);
1178 if (geti(cleantoken, &cyls, &i))
1179 break;
1181 * Check the bounds - cyls is number of cylinders
1183 if (cyls > (bounds->upper/spc())) {
1184 err_print("`%dc' is out of range\n", cyls);
1185 break;
1188 * Convert cylinders to blocks and return
1190 return (cyls * spc());
1191 case 'm':
1193 * Convert token from megabytes to a block number.
1195 if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1196 err_print("`%s' is not recognized\n",
1197 cleantoken);
1198 break;
1201 * Check the bounds
1203 if (nmegs > bn2mb(bounds->upper)) {
1204 err_print("`%1.2fmb' is out of range\n", nmegs);
1205 break;
1208 * Convert to blocks
1210 bn64 = mb2bn(nmegs);
1212 * Round value up to nearest cylinder
1214 i = spc();
1215 bn64 = ((bn64 + (i-1)) / i) * i;
1216 return (bn64);
1217 case 'g':
1219 * Convert token from gigabytes to a block number.
1221 if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
1222 err_print("`%s' is not recognized\n",
1223 cleantoken);
1224 break;
1227 * Check the bounds
1229 if (ngigs > bn2gb(bounds->upper)) {
1230 err_print("`%1.2fgb' is out of range\n", ngigs);
1231 break;
1234 * Convert to blocks
1236 bn64 = gb2bn(ngigs);
1238 * Round value up to nearest cylinder
1240 i = spc();
1241 bn64 = ((bn64 + (i-1)) / i) * i;
1242 return (bn64);
1243 default:
1244 err_print(
1245 "Please specify units in either b(blocks), c(cylinders), m(megabytes) \
1246 or g(gigabytes)\n");
1247 break;
1249 break;
1251 case FIO_ECYL:
1253 * Parameter is the bounds of legal block numbers.
1255 bounds = (struct bounds *)&param->io_bounds;
1256 assert(bounds->lower == 0);
1259 * Print help message if required.
1261 if (help) {
1262 fmt_print("Expecting up to %llu blocks,",
1263 bounds->upper);
1264 fmt_print(" %u cylinders, ",
1265 bn2c(bounds->upper));
1266 fmt_print(" %u end cylinder, ",
1267 (uint_t)(bounds->upper / spc()));
1268 fmt_print(" %1.2f megabytes, ",
1269 bn2mb(bounds->upper));
1270 fmt_print("or %1.2f gigabytes\n",
1271 bn2gb(bounds->upper));
1272 break;
1276 * Parse the first token: try to find 'b', 'c', 'e'
1277 * or 'm'
1279 s = cleantoken;
1280 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
1281 s++;
1285 * If we found a conversion specifier, second token is
1286 * unused Otherwise, the second token should supply it.
1288 if (*s != 0) {
1289 value = *s;
1290 *s = 0;
1291 } else {
1292 value = cleantoken2[0];
1296 * If the token is the wild card, simply supply the max
1297 * This order allows the user to specify the maximum in
1298 * either blocks/cyls/megabytes - a convenient fiction.
1300 if (strcmp(cleantoken, WILD_STRING) == 0) {
1301 return (bounds->upper);
1305 * Allow the user to specify zero with no units,
1306 * by just defaulting to cylinders.
1309 if (value != 'e' && strcmp(cleantoken, "0") == 0) {
1310 value = 'c';
1315 * If there's a decimal point, but no unit
1316 * specification, let's assume megabytes.
1318 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
1319 value = 'm';
1323 * Handle each unit type we support
1325 switch (value) {
1326 case 'b':
1328 * Convert token to a disk block number.
1330 if (geti64(cleantoken, &bn64, &bounds->upper))
1331 break;
1333 * Check to be sure it is within the
1334 * legal bounds.
1336 if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
1337 err_print(
1338 "`%llub' is out of the range %llu to %llu\n",
1339 bn64, bounds->lower, bounds->upper);
1340 break;
1344 * Verify the block lies on a cylinder
1345 * boundary
1347 if ((bn64 % spc()) != 0) {
1348 err_print(
1349 "partition size must be a multiple of %u "
1350 "blocks to lie on a cylinder boundary\n",
1351 spc());
1352 err_print(
1353 "%llu blocks is approximately %u cylinders,"
1354 " %1.2f megabytes or %1.2f gigabytes\n",
1355 bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
1356 break;
1359 return (bn64);
1361 case 'e':
1363 * Token is ending cylinder
1366 /* convert token to integer */
1367 if (geti(cleantoken, &cylno, NULL)) {
1368 break;
1372 * check that input cylno isn't before the current
1373 * starting cylinder number. Note that we are NOT
1374 * using the starting cylinder from
1375 * cur_parts->pinfo_map[].dkl_cylno!
1377 if (cylno < part_deflt->start_cyl) {
1378 err_print(
1379 "End cylinder must fall on or after start cylinder %u\n",
1380 part_deflt->start_cyl);
1381 break;
1385 * calculate cylinder number of upper boundary, and
1386 * verify that our input is within range
1388 i = (bn2c(bounds->upper) + part_deflt->start_cyl - 1);
1390 if (cylno > i) {
1391 err_print(
1392 "End cylinder %d is beyond max cylinder %d\n",
1393 cylno, i);
1394 break;
1398 * calculate number of cylinders based on input
1400 cyls = ((cylno - part_deflt->start_cyl) + 1);
1402 return (cyls * spc());
1404 case 'c':
1406 * Convert token from a number of
1407 * cylinders to a number of blocks.
1409 i = bn2c(bounds->upper);
1410 if (geti(cleantoken, &cyls, &i))
1411 break;
1414 * Check the bounds - cyls is number of
1415 * cylinders
1417 if (cyls > (bounds->upper/spc())) {
1418 err_print("`%dc' is out of range\n", cyls);
1419 break;
1423 * Convert cylinders to blocks and
1424 * return
1426 return (cyls * spc());
1428 case 'm':
1430 * Convert token from megabytes to a
1431 * block number.
1433 if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1434 err_print("`%s' is not recognized\n",
1435 cleantoken);
1436 break;
1440 * Check the bounds
1442 if (nmegs > bn2mb(bounds->upper)) {
1443 err_print("`%1.2fmb' is out of range\n", nmegs);
1444 break;
1448 * Convert to blocks
1450 bn64 = mb2bn(nmegs);
1453 * Round value up to nearest cylinder
1455 i = spc();
1456 bn64 = ((bn64 + (i-1)) / i) * i;
1457 return (bn64);
1459 case 'g':
1461 * Convert token from gigabytes to a
1462 * block number.
1464 if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
1465 err_print("`%s' is not recognized\n",
1466 cleantoken);
1467 break;
1471 * Check the bounds
1473 if (ngigs > bn2gb(bounds->upper)) {
1474 err_print("`%1.2fgb' is out of range\n", ngigs);
1475 break;
1479 * Convert to blocks
1481 bn64 = gb2bn(ngigs);
1484 * Round value up to nearest cylinder
1486 i = spc();
1487 bn64 = ((bn64 + (i-1)) / i) * i;
1488 return (bn64);
1490 default:
1491 err_print(
1492 "Please specify units in either b(blocks), c(cylinders), e(end cylinder),\n");
1493 err_print("m(megabytes) or g(gigabytes)\n");
1494 break;
1496 break;
1497 case FIO_EFI:
1499 * Parameter is the bounds of legal block numbers.
1501 bounds = (struct bounds *)&param->io_bounds;
1504 * Print help message if required.
1506 if (help) {
1507 fmt_print("Expecting up to %llu sectors,",
1508 cur_parts->etoc->efi_last_u_lba);
1509 fmt_print("or %llu megabytes,",
1510 (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
1511 (1024 * 1024));
1512 fmt_print("or %llu gigabytes\n",
1513 (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
1514 (1024 * 1024 * 1024));
1515 fmt_print("or %llu terabytes\n",
1516 (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
1517 ((uint64_t)1024 * 1024 * 1024 * 1024));
1518 break;
1522 * Parse the first token: try to find 'b', 'c', 'e'
1523 * or 'm'
1525 s = cleantoken;
1526 while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
1527 s++;
1531 * If we found a conversion specifier, second token is
1532 * unused Otherwise, the second token should supply it.
1534 if (*s != 0) {
1535 value = *s;
1536 *s = 0;
1537 } else {
1538 value = cleantoken2[0];
1542 * If the token is the wild card, simply supply the max
1543 * This order allows the user to specify the maximum in
1544 * either blocks/cyls/megabytes - a convenient fiction.
1546 if (strcmp(cleantoken, WILD_STRING) == 0) {
1547 return (bounds->upper - EFI_MIN_RESV_SIZE -
1548 efi_deflt->start_sector);
1552 * Allow the user to specify zero with no units,
1553 * by just defaulting to sectors.
1556 if (value != 'e' && strcmp(cleantoken, "0") == 0) {
1557 value = 'm';
1562 * If there's a decimal point, but no unit
1563 * specification, let's assume megabytes.
1565 if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
1566 value = 'm';
1570 * Handle each unit type we support
1572 switch (value) {
1573 case 'b':
1575 * Token is number of blocks
1577 if (geti64(cleantoken, &blokno, (uint64_t *)NULL)) {
1578 break;
1580 if (blokno > bounds->upper) {
1581 err_print(
1582 "Number of blocks must be less that the total available blocks.\n");
1583 break;
1585 return (blokno);
1587 case 'e':
1589 * Token is ending block number
1592 /* convert token to integer */
1593 if (geti64(cleantoken, &blokno, (uint64_t *)NULL)) {
1594 break;
1598 * Some sanity check
1600 if (blokno < efi_deflt->start_sector) {
1601 err_print(
1602 "End Sector must fall on or after start sector %llu\n",
1603 efi_deflt->start_sector);
1604 break;
1608 * verify that our input is within range
1610 if (blokno > cur_parts->etoc->efi_last_u_lba) {
1611 err_print(
1612 "End Sector %llu is beyond max Sector %llu\n",
1613 blokno, cur_parts->etoc->efi_last_u_lba);
1614 break;
1618 * calculate number of blocks based on input
1621 return (blokno - efi_deflt->start_sector + 1);
1623 case 'm':
1625 * Convert token from megabytes to a
1626 * block number.
1628 if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1629 err_print("`%s' is not recognized\n",
1630 cleantoken);
1631 break;
1635 * Check the bounds
1637 if (nmegs > bn2mb(bounds->upper - bounds->lower)) {
1638 err_print("`%1.2fmb' is out of range\n", nmegs);
1639 break;
1642 return (mb2bn(nmegs));
1644 case 'g':
1645 if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1646 err_print("`%s' is not recognized\n",
1647 cleantoken);
1648 break;
1650 if (nmegs > bn2gb(bounds->upper - bounds->lower)) {
1651 err_print("`%1.2fgb' is out of range\n", nmegs);
1652 break;
1655 return (gb2bn(nmegs));
1657 case 't':
1658 if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1659 err_print("`%s' is not recognized\n",
1660 cleantoken);
1661 break;
1663 if (nmegs > bn2tb(bounds->upper - bounds->lower)) {
1664 err_print("`%1.2ftb' is out of range\n", nmegs);
1665 break;
1667 return (uint64_t)((float)nmegs * 1024.0 *
1668 1024.0 * 1024.0 * 1024.0 / cur_blksz);
1670 default:
1671 err_print(
1672 "Please specify units in either b(number of blocks), e(end sector),\n");
1673 err_print(" g(gigabytes), m(megabytes)");
1674 err_print(" or t(terabytes)\n");
1675 break;
1677 break;
1680 * If we don't recognize the input type, it's bad news.
1682 default:
1683 err_print("Error: unknown input type.\n");
1684 fullabort();
1687 * If we get here, it's because some error kept us from accepting
1688 * the token. If we are running out of a command file, gracefully
1689 * leave the program. If we are interacting with the user, simply
1690 * reprompt. If the token was in the pipe, abort the current command.
1692 if (option_f)
1693 fullabort();
1694 else if (interactive)
1695 goto reprompt;
1696 else
1697 cmdabort(SIGINT);
1699 * Never actually reached.
1701 return (-1);
1705 * Print input choices
1707 static void
1708 print_input_choices(type, param)
1709 int type;
1710 u_ioparam_t *param;
1712 char **sp;
1713 slist_t *lp;
1714 int width;
1715 int col;
1716 int ncols;
1718 switch (type) {
1719 case FIO_CSTR:
1720 fmt_print("Expecting one of the following:\n");
1721 goto common;
1723 case FIO_MSTR:
1724 fmt_print("Expecting one of the following: ");
1725 fmt_print("(abbreviations ok):\n");
1726 common:
1727 for (sp = (char **)param->io_charlist; *sp != NULL; sp++) {
1728 fmt_print("\t%s\n", *sp);
1730 break;
1732 case FIO_SLIST:
1733 fmt_print("Expecting one of the following: ");
1734 fmt_print("(abbreviations ok):\n");
1736 * Figure out the width of the widest string
1738 width = slist_widest_str((slist_t *)param->io_slist);
1739 width += 4;
1741 * If the help messages are empty, print the
1742 * possible choices in left-justified columns
1744 lp = (slist_t *)param->io_slist;
1745 if (*lp->help == 0) {
1746 col = 0;
1747 ncols = 60 / width;
1748 for (; lp->str != NULL; lp++) {
1749 if (col == 0)
1750 fmt_print("\t");
1751 ljust_print(lp->str,
1752 (++col == ncols) ? 0 : width);
1753 if (col == ncols) {
1754 col = 0;
1755 fmt_print("\n");
1758 if (col != 0)
1759 fmt_print("\n");
1760 } else {
1762 * With help messages, print each choice,
1763 * and help message, on its own line.
1765 for (; lp->str != NULL; lp++) {
1766 fmt_print("\t");
1767 ljust_print(lp->str, width);
1768 fmt_print("- %s\n", lp->help);
1771 break;
1773 default:
1774 err_print("Error: unknown input type.\n");
1775 fullabort();
1778 fmt_print("\n");
1783 * Search a string list for a particular string.
1784 * Use minimum recognition, to accept unique abbreviations
1785 * Return the number of possible matches found.
1786 * If only one match was found, return the arbitrary value
1787 * associated with the matched string in match_value.
1790 find_value(slist, match_str, match_value)
1791 slist_t *slist;
1792 char *match_str;
1793 int *match_value;
1795 int i;
1796 int nmatches;
1797 int length;
1798 int match_length;
1800 nmatches = 0;
1801 length = 0;
1803 match_length = strlen(match_str);
1805 for (; slist->str != NULL; slist++) {
1807 * See how many characters of the token match
1809 i = strcnt(match_str, slist->str);
1811 * If it's not the whole token, then it's not a match.
1813 if (i < match_length)
1814 continue;
1816 * If it ties with another input, remember that.
1818 if (i == length)
1819 nmatches++;
1821 * If it matches the most so far, record that.
1823 if (i > length) {
1824 *match_value = slist->value;
1825 nmatches = 1;
1826 length = i;
1830 return (nmatches);
1834 * Search a string list for a particular value.
1835 * Return the string associated with that value.
1837 char *
1838 find_string(slist, match_value)
1839 slist_t *slist;
1840 int match_value;
1842 for (; slist->str != NULL; slist++) {
1843 if (slist->value == match_value) {
1844 return (slist->str);
1848 return (NULL);
1852 * Return the width of the widest string in an slist
1854 static int
1855 slist_widest_str(slist)
1856 slist_t *slist;
1858 int i;
1859 int width;
1861 width = 0;
1862 for (; slist->str != NULL; slist++) {
1863 if ((i = strlen(slist->str)) > width)
1864 width = i;
1867 return (width);
1871 * Print a string left-justified to a fixed width.
1873 static void
1874 ljust_print(str, width)
1875 char *str;
1876 int width;
1878 int i;
1880 fmt_print("%s", str);
1881 for (i = width - strlen(str); i > 0; i--) {
1882 fmt_print(" ");
1887 * This routine is a modified version of printf. It handles the cases
1888 * of silent mode and logging; other than that it is identical to the
1889 * library version.
1891 /*PRINTFLIKE1*/
1892 void
1893 fmt_print(char *format, ...)
1895 va_list ap;
1897 va_start(ap, format);
1900 * If we are running silent, skip it.
1902 if (option_s == 0) {
1904 * Do the print to standard out.
1906 if (need_newline) {
1907 (void) printf("\n");
1909 (void) vprintf(format, ap);
1911 * If we are logging, also print to the log file.
1913 if (log_file) {
1914 if (need_newline) {
1915 (void) fprintf(log_file, "\n");
1917 (void) vfprintf(log_file, format, ap);
1918 (void) fflush(log_file);
1922 need_newline = 0;
1924 va_end(ap);
1928 * This routine is a modified version of printf. It handles the cases
1929 * of silent mode; other than that it is identical to the
1930 * library version. It differs from the above printf in that it does
1931 * not print the message to a log file.
1933 /*PRINTFLIKE1*/
1934 void
1935 nolog_print(char *format, ...)
1937 va_list ap;
1939 va_start(ap, format);
1942 * If we are running silent, skip it.
1944 if (option_s == 0) {
1946 * Do the print to standard out.
1948 if (need_newline) {
1949 (void) printf("\n");
1951 (void) vprintf(format, ap);
1954 va_end(ap);
1956 need_newline = 0;
1960 * This routine is a modified version of printf. It handles the cases
1961 * of silent mode, and only prints the message to the log file, not
1962 * stdout. Other than that is identical to the library version.
1964 /*PRINTFLIKE1*/
1965 void
1966 log_print(char *format, ...)
1968 va_list ap;
1970 va_start(ap, format);
1973 * If we are running silent, skip it.
1975 if (option_s == 0) {
1977 * Do the print to the log file.
1979 if (need_newline) {
1980 (void) fprintf(log_file, "\n");
1982 (void) vfprintf(log_file, format, ap);
1983 (void) fflush(log_file);
1986 va_end(ap);
1988 need_newline = 0;
1992 * This routine is a modified version of printf. It prints the message
1993 * to stderr, and to the log file is appropriate.
1994 * Other than that is identical to the library version.
1996 /*PRINTFLIKE1*/
1997 void
1998 err_print(char *format, ...)
2000 va_list ap;
2002 va_start(ap, format);
2005 * Flush anything pending to stdout
2007 if (need_newline) {
2008 (void) printf("\n");
2010 (void) fflush(stdout);
2012 * Do the print to stderr.
2014 (void) vfprintf(stderr, format, ap);
2016 * If we are logging, also print to the log file.
2018 if (log_file) {
2019 if (need_newline) {
2020 (void) fprintf(log_file, "\n");
2022 (void) vfprintf(log_file, format, ap);
2023 (void) fflush(log_file);
2025 va_end(ap);
2027 need_newline = 0;
2031 * Print a number of characters from a buffer. The buffer
2032 * does not need to be null-terminated. Since the data
2033 * may be coming from a device, we cannot be sure the
2034 * data is not crud, so be rather defensive.
2036 void
2037 print_buf(buf, nbytes)
2038 char *buf;
2039 int nbytes;
2041 int c;
2043 while (nbytes-- > 0) {
2044 c = *buf++;
2045 if (isascii(c) && isprint(c)) {
2046 fmt_print("%c", c);
2047 } else
2048 break;
2052 #ifdef not
2054 * This routine prints out a message describing the given ctlr.
2055 * The message is identical to the one printed by the kernel during
2056 * booting.
2058 void
2059 pr_ctlrline(ctlr)
2060 register struct ctlr_info *ctlr;
2063 fmt_print(" %s%d at %s 0x%x ",
2064 ctlr->ctlr_cname, ctlr->ctlr_num,
2065 space2str(ctlr->ctlr_space), ctlr->ctlr_addr);
2066 if (ctlr->ctlr_vec != 0)
2067 fmt_print("vec 0x%x ", ctlr->ctlr_vec);
2068 else
2069 fmt_print("pri %d ", ctlr->ctlr_prio);
2070 fmt_print("\n");
2072 #endif /* not */
2075 * This routine prints out a message describing the given disk.
2076 * The message is identical to the one printed by the kernel during
2077 * booting.
2079 void
2080 pr_diskline(disk, num)
2081 register struct disk_info *disk;
2082 int num;
2084 struct ctlr_info *ctlr = disk->disk_ctlr;
2085 struct disk_type *type = disk->disk_type;
2087 fmt_print(" %4d. %s ", num, disk->disk_name);
2088 if ((type != NULL) && (disk->label_type == L_TYPE_SOLARIS)) {
2089 fmt_print("<%s cyl %u alt %u hd %u sec %u>",
2090 type->dtype_asciilabel, type->dtype_ncyl,
2091 type->dtype_acyl, type->dtype_nhead,
2092 type->dtype_nsect);
2093 } else if ((type != NULL) && (disk->label_type == L_TYPE_EFI)) {
2094 cur_blksz = disk->disk_lbasize;
2095 print_efi_string(type->vendor, type->product,
2096 type->revision, type->capacity);
2097 } else if (disk->disk_flags & DSK_RESERVED) {
2098 fmt_print("<drive not available: reserved>");
2099 } else if (disk->disk_flags & DSK_UNAVAILABLE) {
2100 fmt_print("<drive not available>");
2101 } else {
2102 fmt_print("<drive type unknown>");
2104 if (chk_volname(disk)) {
2105 fmt_print(" ");
2106 print_volname(disk);
2108 fmt_print("\n");
2110 if (disk->devfs_name != NULL) {
2111 fmt_print(" %s\n", disk->devfs_name);
2112 } else {
2113 fmt_print(" %s%d at %s%d slave %d\n",
2114 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
2115 ctlr->ctlr_cname, ctlr->ctlr_num,
2116 disk->disk_dkinfo.dki_slave);
2119 #ifdef OLD
2120 fmt_print(" %4d. %s at %s%d slave %d", num, disk->disk_name,
2121 ctlr->ctlr_cname, ctlr->ctlr_num, disk->disk_dkinfo.dki_slave);
2122 if (chk_volname(disk)) {
2123 fmt_print(": ");
2124 print_volname(disk);
2126 fmt_print("\n");
2127 if (type != NULL) {
2128 fmt_print(
2129 " %s%d: <%s cyl %u alt %u hd %u sec %u>\n",
2130 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
2131 type->dtype_asciilabel, type->dtype_ncyl,
2132 type->dtype_acyl, type->dtype_nhead,
2133 type->dtype_nsect);
2134 } else {
2135 fmt_print(" %s%d: <drive type unknown>\n",
2136 ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit);
2138 #endif /* OLD */
2142 * This routine prints out a given disk block number in cylinder/head/sector
2143 * format. It uses the printing routine passed in to do the actual output.
2145 void
2146 pr_dblock(void (*func)(char *, ...), diskaddr_t bn)
2148 if (cur_label == L_TYPE_SOLARIS) {
2149 (*func)("%u/%u/%u", bn2c(bn),
2150 bn2h(bn), bn2s(bn));
2151 } else {
2152 (*func)("%llu", bn);
2157 * This routine inputs a character from the data file. It understands
2158 * the use of '\' to prevent interpretation of a newline. It also keeps
2159 * track of the current line in the data file via a global variable.
2161 static int
2162 sup_inputchar()
2164 int c;
2167 * Input the character.
2169 c = getc(data_file);
2171 * If it's not a backslash, return it.
2173 if (c != '\\')
2174 return (c);
2176 * It was a backslash. Get the next character.
2178 c = getc(data_file);
2180 * If it was a newline, update the line counter and get the next
2181 * character.
2183 if (c == '\n') {
2184 data_lineno++;
2185 c = getc(data_file);
2188 * Return the character.
2190 return (c);
2194 * This routine pushes a character back onto the input pipe for the data file.
2196 static void
2197 sup_pushchar(c)
2198 int c;
2200 (void) ungetc(c, data_file);
2204 * Variables to support pushing back tokens
2206 static int have_pushed_token = 0;
2207 static TOKEN pushed_buf;
2208 static int pushed_token;
2211 * This routine inputs a token from the data file. A token is a series
2212 * of contiguous non-white characters or a recognized special delimiter
2213 * character. Use of the wrapper lets us always have the value of the
2214 * last token around, which is useful for error recovery.
2217 sup_gettoken(buf)
2218 char *buf;
2220 last_token_type = sup_get_token(buf);
2221 return (last_token_type);
2224 static int
2225 sup_get_token(buf)
2226 char *buf;
2228 char *ptr = buf;
2229 int c, quoted = 0;
2232 * First check for presence of push-backed token.
2233 * If so, return it.
2235 if (have_pushed_token) {
2236 have_pushed_token = 0;
2237 bcopy(pushed_buf, buf, TOKEN_SIZE+1);
2238 return (pushed_token);
2241 * Zero out the returned token buffer
2243 bzero(buf, TOKEN_SIZE + 1);
2245 * Strip off leading white-space.
2247 while ((isspace(c = sup_inputchar())) && (c != '\n'))
2250 * Read in characters until we hit unquoted white-space.
2252 for (; !isspace(c) || quoted; c = sup_inputchar()) {
2254 * If we hit eof, that's a token.
2256 if (feof(data_file))
2257 return (SUP_EOF);
2259 * If we hit a double quote, change the state of quoting.
2261 if (c == '"') {
2262 quoted = !quoted;
2263 continue;
2266 * If we hit a newline, that delimits a token.
2268 if (c == '\n')
2269 break;
2271 * If we hit any nonquoted special delimiters, that delimits
2272 * a token.
2274 if (!quoted && (c == '=' || c == ',' || c == ':' ||
2275 c == '#' || c == '|' || c == '&' || c == '~'))
2276 break;
2278 * Store the character if there's room left.
2280 if (ptr - buf < TOKEN_SIZE)
2281 *ptr++ = (char)c;
2284 * If we stored characters in the buffer, then we inputted a string.
2285 * Push the delimiter back into the pipe and return the string.
2287 if (ptr - buf > 0) {
2288 sup_pushchar(c);
2289 return (SUP_STRING);
2292 * We didn't input a string, so we must have inputted a known delimiter.
2293 * store the delimiter in the buffer, so it will get returned.
2295 buf[0] = c;
2297 * Switch on the delimiter. Return the appropriate value for each one.
2299 switch (c) {
2300 case '=':
2301 return (SUP_EQL);
2302 case ':':
2303 return (SUP_COLON);
2304 case ',':
2305 return (SUP_COMMA);
2306 case '\n':
2307 return (SUP_EOL);
2308 case '|':
2309 return (SUP_OR);
2310 case '&':
2311 return (SUP_AND);
2312 case '~':
2313 return (SUP_TILDE);
2314 case '#':
2316 * For comments, we flush out the rest of the line and return
2317 * an EOL.
2319 while ((c = sup_inputchar()) != '\n' && !feof(data_file))
2321 if (feof(data_file))
2322 return (SUP_EOF);
2323 else
2324 return (SUP_EOL);
2326 * Shouldn't ever get here.
2328 default:
2329 return (SUP_STRING);
2334 * Push back a token
2336 void
2337 sup_pushtoken(token_buf, token_type)
2338 char *token_buf;
2339 int token_type;
2342 * We can only push one token back at a time
2344 assert(have_pushed_token == 0);
2346 have_pushed_token = 1;
2347 bcopy(token_buf, pushed_buf, TOKEN_SIZE+1);
2348 pushed_token = token_type;
2352 * Get an entire line of input. Handles logging, comments,
2353 * and EOF.
2355 void
2356 get_inputline(line, nbytes)
2357 char *line;
2358 int nbytes;
2360 char *p = line;
2361 int c;
2364 * Remove any leading white-space and comments
2366 do {
2367 while ((isspace(c = getchar())) && (c != '\n'))
2369 } while (c == COMMENT_CHAR);
2371 * Loop on each character until end of line
2373 while (c != '\n') {
2375 * If we hit eof, get out.
2377 if (checkeof()) {
2378 fullabort();
2381 * Add the character to the buffer.
2383 if (nbytes > 1) {
2384 *p++ = (char)c;
2385 nbytes --;
2388 * Get the next character.
2390 c = getchar();
2393 * Null terminate the token.
2395 *p = 0;
2397 * Indicate that we've emptied the pipe
2399 token_present = 0;
2401 * If we're running out of a file, echo the line to
2402 * the user, otherwise if we're logging, copy the
2403 * input to the log file.
2405 if (option_f) {
2406 fmt_print("%s\n", line);
2407 } else if (log_file) {
2408 log_print("%s\n", line);
2413 * execute the shell escape command
2416 execute_shell(s, buff_size)
2417 char *s;
2418 size_t buff_size;
2420 struct termio termio;
2421 struct termios tty;
2422 int tty_flag, i, j;
2423 char *shell_name;
2424 static char *default_shell = "/bin/sh";
2426 tty_flag = -1;
2428 if (*s == '\0') {
2429 shell_name = getenv("SHELL");
2431 if (shell_name == NULL) {
2432 shell_name = default_shell;
2434 if (strlcpy(s, shell_name, buff_size) >=
2435 buff_size) {
2436 err_print("Error: Shell command ($SHELL) too long.\n");
2437 fullabort();
2441 /* save tty information */
2443 if (isatty(0)) {
2444 if (ioctl(0, TCGETS, &tty) == 0)
2445 tty_flag = 1;
2446 else {
2447 if (ioctl(0, TCGETA, &termio) == 0) {
2448 tty_flag = 0;
2449 tty.c_iflag = termio.c_iflag;
2450 tty.c_oflag = termio.c_oflag;
2451 tty.c_cflag = termio.c_cflag;
2452 tty.c_lflag = termio.c_lflag;
2453 for (i = 0; i < NCC; i++)
2454 tty.c_cc[i] = termio.c_cc[i];
2459 /* close the current file descriptor */
2460 if (cur_disk != NULL) {
2461 (void) close(cur_file);
2464 /* execute the shell escape */
2465 (void) system(s);
2467 /* reopen file descriptor if one was open before */
2468 if (cur_disk != NULL) {
2469 if ((cur_file = open_disk(cur_disk->disk_path,
2470 O_RDWR | O_NDELAY)) < 0) {
2471 err_print("Error: can't reopen selected disk '%s'. \n",
2472 cur_disk->disk_name);
2473 fullabort();
2477 /* Restore tty information */
2479 if (isatty(0)) {
2480 if (tty_flag > 0)
2481 (void) ioctl(0, TCSETSW, &tty);
2482 else if (tty_flag == 0) {
2483 termio.c_iflag = tty.c_iflag;
2484 termio.c_oflag = tty.c_oflag;
2485 termio.c_cflag = tty.c_cflag;
2486 termio.c_lflag = tty.c_lflag;
2487 for (j = 0; j < NCC; j++)
2488 termio.c_cc[j] = tty.c_cc[j];
2489 (void) ioctl(0, TCSETAW, &termio);
2492 if (isatty(1)) {
2493 fmt_print("\n[Hit Return to continue] \n");
2494 (void) fflush(stdin);
2495 if (getchar() == EOF)
2496 fullabort();
2499 return (0);
2502 void
2503 print_efi_string(char *vendor, char *product, char *revision,
2504 uint64_t capacity)
2506 char *new_vendor;
2507 char *new_product;
2508 char *new_revision;
2509 char capacity_string[10];
2510 float scaled;
2511 int i;
2513 /* Strip whitespace from the end of inquiry strings */
2514 new_vendor = strdup(vendor);
2515 if (new_vendor == NULL)
2516 return;
2518 for (i = (strlen(new_vendor) - 1); i >= 0; i--) {
2519 if (new_vendor[i] != 0x20) {
2520 new_vendor[i+1] = '\0';
2521 break;
2525 new_product = strdup(product);
2526 if (new_product == NULL) {
2527 free(new_vendor);
2528 return;
2531 for (i = (strlen(new_product) - 1); i >= 0; i--) {
2532 if (new_product[i] != 0x20) {
2533 new_product[i+1] = '\0';
2534 break;
2538 new_revision = strdup(revision);
2539 if (new_product == NULL) {
2540 free(new_vendor);
2541 free(new_product);
2542 return;
2545 for (i = (strlen(new_revision) - 1); i >= 0; i--) {
2546 if (new_revision[i] != 0x20) {
2547 new_revision[i+1] = '\0';
2548 break;
2552 /* Now build size string */
2553 scaled = bn2mb(capacity);
2554 if (scaled >= (float)1024.0 * 1024) {
2555 (void) snprintf(capacity_string, sizeof (capacity_string),
2556 "%.2fTB", scaled/((float)1024.0 * 1024));
2557 } else if (scaled >= (float)1024.0) {
2558 (void) snprintf(capacity_string, sizeof (capacity_string),
2559 "%.2fGB", scaled/(float)1024.0);
2560 } else {
2561 (void) snprintf(capacity_string, sizeof (capacity_string),
2562 "%.2fMB", scaled);
2565 fmt_print("<%s-%s-%s-%s>",
2566 new_vendor, new_product, new_revision, capacity_string);
2568 free(new_revision);
2569 free(new_product);
2570 free(new_vendor);