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]
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.
39 #include <sys/termio.h>
40 #include <sys/termios.h>
44 #include "menu_partition.h"
49 extern int data_lineno
;
50 extern char *space2str();
54 * This variable is used to determine whether a token is present in the pipe
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;
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
);
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
);
103 * This routine pushes the given character back onto the input stream.
109 (void) ungetc(c
, stdin
);
113 * This routine checks the input stream for an eof condition.
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.
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
) {
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.
157 * If we hit a double quote, change the state of quotedness.
162 * If there's room in the buffer, add the character to the end.
164 else if (ptr
- inbuf
< TOKEN_SIZE
)
167 * Get the next character.
172 * Null terminate the token.
176 * Peel off white-space still in the pipe.
178 while (isspace(c
) && (c
!= '\n'))
181 * If we hit another token, push it back and set state.
195 * This routine removes the leading and trailing spaces from a token.
198 clean_token(cleantoken
, token
)
199 char *cleantoken
, *token
;
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
--) {
222 * This routine checks if a token is already present on the input line
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.
240 * Flush the pipe to eol or eof.
242 while ((getchar() != '\n') && !checkeof())
245 * Mark the pipe empty.
252 * This routine returns the number of characters that are identical
253 * between s1 and s2, stopping as soon as a mismatch is found.
261 while ((*s1
!= '\0') && (*s1
++ == *s2
++))
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
)
280 * If there's a wildcard value and the string is wild, return the
283 if (wild
!= NULL
&& strcmp(str
, WILD_STRING
) == 0)
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.
294 err_print("`%s' is not an integer.\n", str
);
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.
308 geti64(str
, iptr
, wild
)
310 uint64_t *iptr
, *wild
;
315 * If there's a wildcard value and the string is wild, return the
318 if ((wild
!= NULL
) && (strcmp(str
, WILD_STRING
)) == 0) {
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.
329 err_print("`%s' is not an integer.\n", str
);
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.
351 char *cptr
, *hptr
, *sptr
;
358 * Set cylinder pointer to beginning of string.
362 * Look for the first slash.
364 while ((*str
!= '\0') && (*str
!= '/'))
367 * If there wasn't one, convert string to an integer and return it.
370 wild64
= physsects() - 1;
371 if (geti64(cptr
, iptr
, &wild64
))
376 * Null out the slash and set head pointer just beyond it.
381 * Look for the second slash.
383 while ((*str
!= '\0') && (*str
!= '/'))
386 * If there wasn't one, sector pointer points to a .
391 * If there was, null it out and set sector point just beyond it.
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
))
404 if ((cyl
< 0) || (cyl
>= (ncyl
+ acyl
))) {
405 err_print("`%d' is out of range.\n", cyl
);
409 * Convert the head part to an integer and store it.
411 clean_token(buf
, hptr
);
413 if (geti(buf
, &head
, &wild
))
415 if ((head
< 0) || (head
>= nhead
)) {
416 err_print("`%d' is out of range.\n", head
);
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
, §
, &wild
))
426 if ((sect
< 0) || (sect
>= sectors(head
))) {
427 err_print("`%d' is out of range.\n", sect
);
431 * Combine the pieces into a block number and return it.
433 *iptr
= chs2bn(cyl
, head
, sect
);
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.
444 input(type
, promptstr
, delim
, param
, deflt
, cmdflag
)
452 int interactive
, help
, i
, length
, index
, tied
;
455 char **str
, **strings
;
456 TOKEN token
, cleantoken
;
457 TOKEN token2
, cleantoken2
;
459 struct bounds
*bounds
;
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
);
481 help
= interactive
= 0;
483 * If we are inputting a command, flush any current input in the pipe.
485 if (cmdflag
== CMD_INPUT
)
488 * Note whether the token is already present.
495 fmt_print(promptstr
);
497 * If there is a default value, print it in a format appropriate
498 * for the input type.
503 #if !defined(lint) /* caller has aligned the pointer specifying FIO_BN */
504 fmt_print("[%llu, ", *(diskaddr_t
*)deflt
);
505 pr_dblock(fmt_print
, *(diskaddr_t
*)deflt
);
510 fmt_print("[%d]", *deflt
);
514 /* caller is longlong aligned specifying FIO_INT64 */
517 efi_deflt
= (efi_deflt_t
*)deflt
;
519 fmt_print("[%llu]", efi_deflt
->start_sector
);
523 strings
= (char **)param
->io_charlist
;
524 for (i
= 0, str
= strings
; i
< *deflt
; i
++, str
++)
526 fmt_print("[%s]", *str
);
529 fmt_print("[\"%s\"]", (char *)deflt
);
533 * Search for a string matching the default
534 * value. If found, use it. Otherwise
535 * assume the default value is actually
536 * an illegal choice, and default to
537 * the first item in the list.
539 s
= find_string(param
->io_slist
, *deflt
);
540 if (s
== (char *)NULL
) {
541 s
= (param
->io_slist
)->str
;
543 fmt_print("[%s]", s
);
547 * Old-style partition size input, used to
548 * modify complete partition tables
550 blokno
= *(blkaddr32_t
*)deflt
;
551 fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno
,
552 bn2c(blokno
), bn2mb(blokno
), bn2gb(blokno
));
556 * set up pointer to partition defaults
559 part_deflt
= (part_deflt_t
*)deflt
;
562 * Build print format specifier. We use the
563 * starting cylinder number which was entered
564 * before this call to input(), in case the
565 * user has changed it from the value in the
566 * cur_parts->pinfo_map[].dkl_cylno
567 * field for the current parition
571 * Determine the proper default end cylinder:
572 * Start Cyl Default Size End Cylinder
582 if (part_deflt
->deflt_size
== 0) {
583 cylno
= part_deflt
->start_cyl
;
584 } else if (part_deflt
->start_cyl
== 0) {
585 cylno
= bn2c(part_deflt
->deflt_size
) - 1;
587 cylno
= (bn2c(part_deflt
->deflt_size
) +
588 part_deflt
->start_cyl
) - 1;
591 fmt_print("[%ub, %uc, %de, %1.2fmb, %1.2fgb]",
592 part_deflt
->deflt_size
,
593 bn2c(part_deflt
->deflt_size
),
595 bn2mb(part_deflt
->deflt_size
),
596 bn2gb(part_deflt
->deflt_size
));
601 /* caller is longlong aligned when specifying FIO_EFI */
604 efi_deflt
= (efi_deflt_t
*)deflt
;
607 fmt_print("[%llub, %llue, %llumb, %llugb, %llutb]",
608 efi_deflt
->end_sector
,
609 efi_deflt
->start_sector
+ efi_deflt
->end_sector
- 1,
610 (efi_deflt
->end_sector
* cur_blksz
) /
612 (efi_deflt
->end_sector
* cur_blksz
) /
613 (1024 * 1024 * 1024),
614 (efi_deflt
->end_sector
* cur_blksz
) /
615 ((uint64_t)1024 * 1024 * 1024 * 1024));
618 /* no default value for optional input type */
619 fmt_print("[default]");
622 err_print("Error: unknown input type.\n");
627 * Print the delimiter character.
629 fmt_print("%c ", delim
);
631 * Get the token. If we hit eof, exit the program gracefully.
633 if (gettoken(token
) == NULL
)
637 * check if the user has issued (!) , escape to shell
639 if ((cmdflag
== CMD_INPUT
) && (token
[0] == '!')) {
641 /* get the list of arguments to shell command */
642 (void) memset(shell_argv
, 0, sizeof (shell_argv
));
644 /* initialize to the first token... */
648 * ... and then collect all tokens until the end of
649 * the line as arguments
652 /* skip empty tokens. */
656 * If either of the following two strlcat()
657 * operations overflows, report an error and
660 if ((strlcat(shell_argv
, arg
, sizeof (shell_argv
)) >=
661 sizeof (shell_argv
)) ||
662 (strlcat(shell_argv
, " ", sizeof (shell_argv
)) >=
663 sizeof (shell_argv
))) {
664 err_print("Error: Command line too long.\n");
667 } while (token_present
&& (arg
= gettoken(token
)) != NULL
);
669 /* execute the shell command */
670 (void) execute_shell(shell_argv
, sizeof (shell_argv
));
671 redisplay_menu_list((char **)param
->io_charlist
);
678 * Certain commands accept up to two tokens
679 * Unfortunately, this is kind of a hack.
683 if (type
== FIO_CYL
|| type
== FIO_ECYL
) {
685 if (gettoken(token2
) == NULL
)
687 clean_token(cleantoken2
, token2
);
691 * Echo the token back to the user if it was in the pipe or we
692 * are running out of a command file.
694 if (!interactive
|| option_f
) {
695 if (token2
[0] == 0) {
696 fmt_print("%s\n", token
);
698 fmt_print("%s %s\n", token
, token2
);
702 * If we are logging, echo the token to the log file. The else
703 * is necessary here because the above printf will also put the
704 * token in the log file.
707 log_print("%s %s\n", token
, token2
);
710 * If the token was not in the pipe and it wasn't a command, flush
711 * the rest of the line to keep things in sync.
713 if (interactive
&& cmdflag
!= CMD_INPUT
)
716 * Scrub off the white-space.
718 clean_token(cleantoken
, token
);
720 * If the input was a blank line and we weren't prompting
721 * specifically for a blank line...
723 if ((strcmp(cleantoken
, "") == 0) && (type
!= FIO_BLNK
)) {
725 * If there's a default, return it.
728 if (type
== FIO_OSTR
) {
730 * Duplicate and return the default string
732 return ((int)alloc_string((char *)deflt
));
733 } else if (type
== FIO_SLIST
) {
735 * If we can find a match for the default
736 * value in the list, return the default
737 * value. If there's no match for the
738 * default value, it's an illegal
739 * choice. Return the first value in
742 s
= find_string(param
->io_slist
, *deflt
);
743 if ((cur_label
== L_TYPE_EFI
) &&
744 (s
== (char *)NULL
)) {
747 if (s
== (char *)NULL
) {
748 return ((param
->io_slist
)->value
);
752 } else if (type
== FIO_OPINT
) {
754 * The user didn't enter anything
757 } else if (type
== FIO_ECYL
) {
758 return (part_deflt
->deflt_size
);
759 } else if (type
== FIO_INT64
) {
760 return (efi_deflt
->start_sector
);
761 } else if (type
== FIO_EFI
) {
762 return (efi_deflt
->end_sector
);
768 * If the blank was not in the pipe, just reprompt.
774 * If the blank was in the pipe, it's an error.
776 err_print("No default for this entry.\n");
780 * If token is a '?' or a 'h', it is a request for help.
782 if ((strcmp(cleantoken
, "?") == 0) ||
783 (strcmp(cleantoken
, "h") == 0) ||
784 (strcmp(cleantoken
, "help") == 0)) {
788 * Switch on the type of input expected.
792 * Expecting a disk block number.
796 * Parameter is the bounds of legal block numbers.
798 bounds
= (struct bounds
*)¶m
->io_bounds
;
800 * Print help message if required.
803 fmt_print("Expecting a block number from %llu (",
805 pr_dblock(fmt_print
, bounds
->lower
);
806 fmt_print(") to %llu (", bounds
->upper
);
807 pr_dblock(fmt_print
, bounds
->upper
);
812 * Convert token to a disk block number.
814 if (cur_label
== L_TYPE_EFI
) {
815 if (geti64(cleantoken
, (uint64_t *)&bn64
,
819 if (getbn(cleantoken
, &bn64
))
823 * Check to be sure it is within the legal bounds.
825 if ((bn64
< bounds
->lower
) || (bn64
> bounds
->upper
)) {
827 pr_dblock(err_print
, bn64
);
828 err_print("' is out of range.\n");
832 * It's ok, return it.
836 * Expecting an integer.
840 * Parameter is the bounds of legal integers.
842 bounds
= (struct bounds
*)¶m
->io_bounds
;
844 * Print help message if required.
847 fmt_print("Expecting an integer from %llu",
849 fmt_print(" to %llu\n", bounds
->upper
);
853 * Convert the token into an integer.
855 if (geti(cleantoken
, (int *)&bn
, (int *)NULL
))
858 * Check to be sure it is within the legal bounds.
860 if ((bn
< bounds
->lower
) || (bn
> bounds
->upper
)) {
861 err_print("`%lu' is out of range.\n", bn
);
865 * If it's ok, return it.
870 * Parameter is the bounds of legal integers.
872 bounds
= (struct bounds
*)¶m
->io_bounds
;
874 * Print help message if required.
877 fmt_print("Expecting an integer from %llu",
879 fmt_print(" to %llu\n", bounds
->upper
);
883 * Convert the token into an integer.
885 if (geti64(cleantoken
, (uint64_t *)&bn64
, (uint64_t *)NULL
)) {
889 * Check to be sure it is within the legal bounds.
891 if ((bn64
< bounds
->lower
) || (bn64
> bounds
->upper
)) {
892 err_print("`%llu' is out of range.\n", bn64
);
896 * If it's ok, return it.
900 * Expecting an integer, or no input.
904 * Parameter is the bounds of legal integers.
906 bounds
= (struct bounds
*)¶m
->io_bounds
;
908 * Print help message if required.
911 fmt_print("Expecting an integer from %llu",
913 fmt_print(" to %llu, or no input\n", bounds
->upper
);
917 * Convert the token into an integer.
919 if (geti(cleantoken
, (int *)&bn
, (int *)NULL
))
922 * Check to be sure it is within the legal bounds.
924 if ((bn
< bounds
->lower
) || (bn
> bounds
->upper
)) {
925 err_print("`%lu' is out of range.\n", bn
);
929 * For optional case, return 1 indicating that
930 * the user actually did enter something.
936 * Expecting a closed string. This means that the input
937 * string must exactly match one of the strings passed in
942 * The parameter is a null terminated array of character
943 * pointers, each one pointing to a legal input string.
945 strings
= (char **)param
->io_charlist
;
947 * Walk through the legal strings, seeing if any of them
948 * match the token. If a match is made, return the index
949 * of the string that was matched.
951 for (str
= strings
; *str
!= NULL
; str
++)
952 if (strcmp(cleantoken
, *str
) == 0)
953 return (str
- strings
);
955 * Print help message if required.
958 print_input_choices(type
, param
);
960 err_print("`%s' is not expected.\n", cleantoken
);
964 * Expecting a matched string. This means that the input
965 * string must either match one of the strings passed in,
966 * or be a unique abbreviation of one of them.
970 * The parameter is a null terminated array of character
971 * pointers, each one pointing to a legal input string.
973 strings
= (char **)param
->io_charlist
;
974 length
= index
= tied
= 0;
976 * Loop through the legal input strings.
978 for (str
= strings
; *str
!= NULL
; str
++) {
980 * See how many characters of the token match
983 i
= strcnt(cleantoken
, *str
);
985 * If it's not the whole token, then it's not a match.
987 if ((uint_t
)i
< strlen(cleantoken
))
990 * If it ties with another input, remember that.
995 * If it matches the most so far, record that.
998 index
= str
- strings
;
1004 * Print help message if required.
1008 print_input_choices(type
, param
);
1010 err_print("`%s' is not expected.\n",
1016 * If the abbreviation was non-unique, it's an error.
1019 err_print("`%s' is ambiguous.\n", cleantoken
);
1023 * We matched one. Return the index of the string we matched.
1027 * Expecting an open string. This means that any string is legal.
1031 * Print a help message if required.
1034 fmt_print("Expecting a string\n");
1038 * alloc a copy of the string and return it
1040 return ((int)alloc_string(token
));
1043 * Expecting a blank line.
1047 * We are always in non-echo mode when we are inputting
1048 * this type. We echo the newline as a carriage return
1049 * only so the prompt string will be covered over.
1051 nolog_print("\015");
1053 * If we are logging, send a newline to the log file.
1058 * There is no value returned for this type.
1063 * Expecting one of the entries in a string list.
1064 * Accept unique abbreviations.
1065 * Return the value associated with the matched string.
1068 i
= find_value((slist_t
*)param
->io_slist
,
1069 cleantoken
, &value
);
1074 * Print help message if required.
1078 print_input_choices(type
, param
);
1081 err_print("`%s' not expected.\n",
1084 err_print("`%s' is ambiguous.\n",
1091 * Cylinder size input when modifying a complete partition map
1095 * Parameter is the bounds of legal block numbers.
1097 bounds
= (struct bounds
*)¶m
->io_bounds
;
1098 assert(bounds
->lower
== 0);
1100 * Print help message if required.
1103 fmt_print("Expecting up to %llu blocks,",
1105 fmt_print(" %u cylinders, ", bn2c(bounds
->upper
));
1106 fmt_print(" %1.2f megabytes, ", bn2mb(bounds
->upper
));
1107 fmt_print("or %1.2f gigabytes\n", bn2gb(bounds
->upper
));
1111 * Parse the first token: try to find 'b', 'c' or 'm'
1114 while (*s
&& (isdigit(*s
) || (*s
== '.') || (*s
== '$'))) {
1118 * If we found a conversion specifier, second token is unused
1119 * Otherwise, the second token should supply it.
1125 value
= cleantoken2
[0];
1128 * If the token is the wild card, simply supply the max
1129 * This order allows the user to specify the maximum in
1130 * either blocks/cyls/megabytes - a convenient fiction.
1132 if (strcmp(cleantoken
, WILD_STRING
) == 0) {
1133 return (bounds
->upper
);
1136 * Allow the user to specify zero with no units,
1137 * by just defaulting to cylinders.
1139 if (strcmp(cleantoken
, "0") == 0) {
1143 * If there's a decimal point, but no unit specification,
1144 * let's assume megabytes.
1146 if ((value
== 0) && (strchr(cleantoken
, '.') != NULL
)) {
1150 * Handle each unit type we support
1155 * Convert token to a disk block number.
1157 if (geti64(cleantoken
, &bn64
, &bounds
->upper
))
1160 * Check to be sure it is within the legal bounds.
1162 if ((bn64
< bounds
->lower
) || (bn64
> bounds
->upper
)) {
1164 "`%llub' is out of the range %llu "
1166 bn64
, bounds
->lower
, bounds
->upper
);
1170 * Verify the block lies on a cylinder boundary
1172 if ((bn64
% spc()) != 0) {
1174 "partition size must be a multiple of "
1175 "%u blocks to lie on a cylinder boundary\n",
1178 "%llu blocks is approximately %u cylinders,"
1179 " %1.2f megabytes or %1.2f gigabytes\n",
1180 bn64
, bn2c(bn64
), bn2mb(bn64
), bn2gb(bn64
));
1186 * Convert token from a number of cylinders to
1187 * a number of blocks.
1189 i
= bn2c(bounds
->upper
);
1190 if (geti(cleantoken
, &cyls
, &i
))
1193 * Check the bounds - cyls is number of cylinders
1195 if (cyls
> (bounds
->upper
/spc())) {
1196 err_print("`%dc' is out of range\n", cyls
);
1200 * Convert cylinders to blocks and return
1202 return (cyls
* spc());
1205 * Convert token from megabytes to a block number.
1207 if (sscanf(cleantoken
, "%f2", &nmegs
) != 1) {
1208 err_print("`%s' is not recognized\n",
1215 if (nmegs
> bn2mb(bounds
->upper
)) {
1216 err_print("`%1.2fmb' is out of range\n", nmegs
);
1222 bn64
= mb2bn(nmegs
);
1224 * Round value up to nearest cylinder
1227 bn64
= ((bn64
+ (i
-1)) / i
) * i
;
1231 * Convert token from gigabytes to a block number.
1233 if (sscanf(cleantoken
, "%f2", &ngigs
) != 1) {
1234 err_print("`%s' is not recognized\n",
1241 if (ngigs
> bn2gb(bounds
->upper
)) {
1242 err_print("`%1.2fgb' is out of range\n", ngigs
);
1248 bn64
= gb2bn(ngigs
);
1250 * Round value up to nearest cylinder
1253 bn64
= ((bn64
+ (i
-1)) / i
) * i
;
1257 "Please specify units in either b(blocks), c(cylinders), m(megabytes) \
1258 or g(gigabytes)\n");
1265 * Parameter is the bounds of legal block numbers.
1267 bounds
= (struct bounds
*)¶m
->io_bounds
;
1268 assert(bounds
->lower
== 0);
1271 * Print help message if required.
1274 fmt_print("Expecting up to %llu blocks,",
1276 fmt_print(" %u cylinders, ",
1277 bn2c(bounds
->upper
));
1278 fmt_print(" %u end cylinder, ",
1279 (uint_t
)(bounds
->upper
/ spc()));
1280 fmt_print(" %1.2f megabytes, ",
1281 bn2mb(bounds
->upper
));
1282 fmt_print("or %1.2f gigabytes\n",
1283 bn2gb(bounds
->upper
));
1288 * Parse the first token: try to find 'b', 'c', 'e'
1292 while (*s
&& (isdigit(*s
) || (*s
== '.') || (*s
== '$'))) {
1297 * If we found a conversion specifier, second token is
1298 * unused Otherwise, the second token should supply it.
1304 value
= cleantoken2
[0];
1308 * If the token is the wild card, simply supply the max
1309 * This order allows the user to specify the maximum in
1310 * either blocks/cyls/megabytes - a convenient fiction.
1312 if (strcmp(cleantoken
, WILD_STRING
) == 0) {
1313 return (bounds
->upper
);
1317 * Allow the user to specify zero with no units,
1318 * by just defaulting to cylinders.
1321 if (value
!= 'e' && strcmp(cleantoken
, "0") == 0) {
1327 * If there's a decimal point, but no unit
1328 * specification, let's assume megabytes.
1330 if ((value
== 0) && (strchr(cleantoken
, '.') != NULL
)) {
1335 * Handle each unit type we support
1340 * Convert token to a disk block number.
1342 if (geti64(cleantoken
, &bn64
, &bounds
->upper
))
1345 * Check to be sure it is within the
1348 if ((bn64
< bounds
->lower
) || (bn64
> bounds
->upper
)) {
1350 "`%llub' is out of the range %llu to %llu\n",
1351 bn64
, bounds
->lower
, bounds
->upper
);
1356 * Verify the block lies on a cylinder
1359 if ((bn64
% spc()) != 0) {
1361 "partition size must be a multiple of %u "
1362 "blocks to lie on a cylinder boundary\n",
1365 "%llu blocks is approximately %u cylinders,"
1366 " %1.2f megabytes or %1.2f gigabytes\n",
1367 bn64
, bn2c(bn64
), bn2mb(bn64
), bn2gb(bn64
));
1375 * Token is ending cylinder
1378 /* convert token to integer */
1379 if (geti(cleantoken
, &cylno
, (int *)NULL
)) {
1384 * check that input cylno isn't before the current
1385 * starting cylinder number. Note that we are NOT
1386 * using the starting cylinder from
1387 * cur_parts->pinfo_map[].dkl_cylno!
1389 if (cylno
< part_deflt
->start_cyl
) {
1391 "End cylinder must fall on or after start cylinder %u\n",
1392 part_deflt
->start_cyl
);
1397 * calculate cylinder number of upper boundary, and
1398 * verify that our input is within range
1400 i
= (bn2c(bounds
->upper
) + part_deflt
->start_cyl
- 1);
1404 "End cylinder %d is beyond max cylinder %d\n",
1410 * calculate number of cylinders based on input
1412 cyls
= ((cylno
- part_deflt
->start_cyl
) + 1);
1414 return (cyls
* spc());
1418 * Convert token from a number of
1419 * cylinders to a number of blocks.
1421 i
= bn2c(bounds
->upper
);
1422 if (geti(cleantoken
, &cyls
, &i
))
1426 * Check the bounds - cyls is number of
1429 if (cyls
> (bounds
->upper
/spc())) {
1430 err_print("`%dc' is out of range\n", cyls
);
1435 * Convert cylinders to blocks and
1438 return (cyls
* spc());
1442 * Convert token from megabytes to a
1445 if (sscanf(cleantoken
, "%f2", &nmegs
) != 1) {
1446 err_print("`%s' is not recognized\n",
1454 if (nmegs
> bn2mb(bounds
->upper
)) {
1455 err_print("`%1.2fmb' is out of range\n", nmegs
);
1462 bn64
= mb2bn(nmegs
);
1465 * Round value up to nearest cylinder
1468 bn64
= ((bn64
+ (i
-1)) / i
) * i
;
1473 * Convert token from gigabytes to a
1476 if (sscanf(cleantoken
, "%f2", &ngigs
) != 1) {
1477 err_print("`%s' is not recognized\n",
1485 if (ngigs
> bn2gb(bounds
->upper
)) {
1486 err_print("`%1.2fgb' is out of range\n", ngigs
);
1493 bn64
= gb2bn(ngigs
);
1496 * Round value up to nearest cylinder
1499 bn64
= ((bn64
+ (i
-1)) / i
) * i
;
1504 "Please specify units in either b(blocks), c(cylinders), e(end cylinder),\n");
1505 err_print("m(megabytes) or g(gigabytes)\n");
1511 * Parameter is the bounds of legal block numbers.
1513 bounds
= (struct bounds
*)¶m
->io_bounds
;
1516 * Print help message if required.
1519 fmt_print("Expecting up to %llu sectors,",
1520 cur_parts
->etoc
->efi_last_u_lba
);
1521 fmt_print("or %llu megabytes,",
1522 (cur_parts
->etoc
->efi_last_u_lba
* cur_blksz
)/
1524 fmt_print("or %llu gigabytes\n",
1525 (cur_parts
->etoc
->efi_last_u_lba
* cur_blksz
)/
1526 (1024 * 1024 * 1024));
1527 fmt_print("or %llu terabytes\n",
1528 (cur_parts
->etoc
->efi_last_u_lba
* cur_blksz
)/
1529 ((uint64_t)1024 * 1024 * 1024 * 1024));
1534 * Parse the first token: try to find 'b', 'c', 'e'
1538 while (*s
&& (isdigit(*s
) || (*s
== '.') || (*s
== '$'))) {
1543 * If we found a conversion specifier, second token is
1544 * unused Otherwise, the second token should supply it.
1550 value
= cleantoken2
[0];
1554 * If the token is the wild card, simply supply the max
1555 * This order allows the user to specify the maximum in
1556 * either blocks/cyls/megabytes - a convenient fiction.
1558 if (strcmp(cleantoken
, WILD_STRING
) == 0) {
1559 return (bounds
->upper
- EFI_MIN_RESV_SIZE
-
1560 efi_deflt
->start_sector
);
1564 * Allow the user to specify zero with no units,
1565 * by just defaulting to sectors.
1568 if (value
!= 'e' && strcmp(cleantoken
, "0") == 0) {
1574 * If there's a decimal point, but no unit
1575 * specification, let's assume megabytes.
1577 if ((value
== 0) && (strchr(cleantoken
, '.') != NULL
)) {
1582 * Handle each unit type we support
1587 * Token is number of blocks
1589 if (geti64(cleantoken
, &blokno
, (uint64_t *)NULL
)) {
1592 if (blokno
> bounds
->upper
) {
1594 "Number of blocks must be less that the total available blocks.\n");
1601 * Token is ending block number
1604 /* convert token to integer */
1605 if (geti64(cleantoken
, &blokno
, (uint64_t *)NULL
)) {
1612 if (blokno
< efi_deflt
->start_sector
) {
1614 "End Sector must fall on or after start sector %llu\n",
1615 efi_deflt
->start_sector
);
1620 * verify that our input is within range
1622 if (blokno
> cur_parts
->etoc
->efi_last_u_lba
) {
1624 "End Sector %llu is beyond max Sector %llu\n",
1625 blokno
, cur_parts
->etoc
->efi_last_u_lba
);
1630 * calculate number of blocks based on input
1633 return (blokno
- efi_deflt
->start_sector
+ 1);
1637 * Convert token from megabytes to a
1640 if (sscanf(cleantoken
, "%f2", &nmegs
) != 1) {
1641 err_print("`%s' is not recognized\n",
1649 if (nmegs
> bn2mb(bounds
->upper
- bounds
->lower
)) {
1650 err_print("`%1.2fmb' is out of range\n", nmegs
);
1654 return (mb2bn(nmegs
));
1657 if (sscanf(cleantoken
, "%f2", &nmegs
) != 1) {
1658 err_print("`%s' is not recognized\n",
1662 if (nmegs
> bn2gb(bounds
->upper
- bounds
->lower
)) {
1663 err_print("`%1.2fgb' is out of range\n", nmegs
);
1667 return (gb2bn(nmegs
));
1670 if (sscanf(cleantoken
, "%f2", &nmegs
) != 1) {
1671 err_print("`%s' is not recognized\n",
1675 if (nmegs
> bn2tb(bounds
->upper
- bounds
->lower
)) {
1676 err_print("`%1.2ftb' is out of range\n", nmegs
);
1679 return (uint64_t)((float)nmegs
* 1024.0 *
1680 1024.0 * 1024.0 * 1024.0 / cur_blksz
);
1684 "Please specify units in either b(number of blocks), e(end sector),\n");
1685 err_print(" g(gigabytes), m(megabytes)");
1686 err_print(" or t(terabytes)\n");
1692 * If we don't recognize the input type, it's bad news.
1695 err_print("Error: unknown input type.\n");
1699 * If we get here, it's because some error kept us from accepting
1700 * the token. If we are running out of a command file, gracefully
1701 * leave the program. If we are interacting with the user, simply
1702 * reprompt. If the token was in the pipe, abort the current command.
1706 else if (interactive
)
1711 * Never actually reached.
1717 * Print input choices
1720 print_input_choices(type
, param
)
1732 fmt_print("Expecting one of the following:\n");
1736 fmt_print("Expecting one of the following: ");
1737 fmt_print("(abbreviations ok):\n");
1739 for (sp
= (char **)param
->io_charlist
; *sp
!= NULL
; sp
++) {
1740 fmt_print("\t%s\n", *sp
);
1745 fmt_print("Expecting one of the following: ");
1746 fmt_print("(abbreviations ok):\n");
1748 * Figure out the width of the widest string
1750 width
= slist_widest_str((slist_t
*)param
->io_slist
);
1753 * If the help messages are empty, print the
1754 * possible choices in left-justified columns
1756 lp
= (slist_t
*)param
->io_slist
;
1757 if (*lp
->help
== 0) {
1760 for (; lp
->str
!= NULL
; lp
++) {
1763 ljust_print(lp
->str
,
1764 (++col
== ncols
) ? 0 : width
);
1774 * With help messages, print each choice,
1775 * and help message, on its own line.
1777 for (; lp
->str
!= NULL
; lp
++) {
1779 ljust_print(lp
->str
, width
);
1780 fmt_print("- %s\n", lp
->help
);
1786 err_print("Error: unknown input type.\n");
1795 * Search a string list for a particular string.
1796 * Use minimum recognition, to accept unique abbreviations
1797 * Return the number of possible matches found.
1798 * If only one match was found, return the arbitrary value
1799 * associated with the matched string in match_value.
1802 find_value(slist
, match_str
, match_value
)
1815 match_length
= strlen(match_str
);
1817 for (; slist
->str
!= NULL
; slist
++) {
1819 * See how many characters of the token match
1821 i
= strcnt(match_str
, slist
->str
);
1823 * If it's not the whole token, then it's not a match.
1825 if (i
< match_length
)
1828 * If it ties with another input, remember that.
1833 * If it matches the most so far, record that.
1836 *match_value
= slist
->value
;
1846 * Search a string list for a particular value.
1847 * Return the string associated with that value.
1850 find_string(slist
, match_value
)
1854 for (; slist
->str
!= NULL
; slist
++) {
1855 if (slist
->value
== match_value
) {
1856 return (slist
->str
);
1860 return ((char *)NULL
);
1864 * Return the width of the widest string in an slist
1867 slist_widest_str(slist
)
1874 for (; slist
->str
!= NULL
; slist
++) {
1875 if ((i
= strlen(slist
->str
)) > width
)
1883 * Print a string left-justified to a fixed width.
1886 ljust_print(str
, width
)
1892 fmt_print("%s", str
);
1893 for (i
= width
- strlen(str
); i
> 0; i
--) {
1899 * This routine is a modified version of printf. It handles the cases
1900 * of silent mode and logging; other than that it is identical to the
1905 fmt_print(char *format
, ...)
1909 va_start(ap
, format
);
1912 * If we are running silent, skip it.
1914 if (option_s
== 0) {
1916 * Do the print to standard out.
1919 (void) printf("\n");
1921 (void) vprintf(format
, ap
);
1923 * If we are logging, also print to the log file.
1927 (void) fprintf(log_file
, "\n");
1929 (void) vfprintf(log_file
, format
, ap
);
1930 (void) fflush(log_file
);
1940 * This routine is a modified version of printf. It handles the cases
1941 * of silent mode; other than that it is identical to the
1942 * library version. It differs from the above printf in that it does
1943 * not print the message to a log file.
1947 nolog_print(char *format
, ...)
1951 va_start(ap
, format
);
1954 * If we are running silent, skip it.
1956 if (option_s
== 0) {
1958 * Do the print to standard out.
1961 (void) printf("\n");
1963 (void) vprintf(format
, ap
);
1972 * This routine is a modified version of printf. It handles the cases
1973 * of silent mode, and only prints the message to the log file, not
1974 * stdout. Other than that is identical to the library version.
1978 log_print(char *format
, ...)
1982 va_start(ap
, format
);
1985 * If we are running silent, skip it.
1987 if (option_s
== 0) {
1989 * Do the print to the log file.
1992 (void) fprintf(log_file
, "\n");
1994 (void) vfprintf(log_file
, format
, ap
);
1995 (void) fflush(log_file
);
2004 * This routine is a modified version of printf. It prints the message
2005 * to stderr, and to the log file is appropriate.
2006 * Other than that is identical to the library version.
2010 err_print(char *format
, ...)
2014 va_start(ap
, format
);
2017 * Flush anything pending to stdout
2020 (void) printf("\n");
2022 (void) fflush(stdout
);
2024 * Do the print to stderr.
2026 (void) vfprintf(stderr
, format
, ap
);
2028 * If we are logging, also print to the log file.
2032 (void) fprintf(log_file
, "\n");
2034 (void) vfprintf(log_file
, format
, ap
);
2035 (void) fflush(log_file
);
2043 * Print a number of characters from a buffer. The buffer
2044 * does not need to be null-terminated. Since the data
2045 * may be coming from a device, we cannot be sure the
2046 * data is not crud, so be rather defensive.
2049 print_buf(buf
, nbytes
)
2055 while (nbytes
-- > 0) {
2057 if (isascii(c
) && isprint(c
)) {
2066 * This routine prints out a message describing the given ctlr.
2067 * The message is identical to the one printed by the kernel during
2072 register struct ctlr_info
*ctlr
;
2075 fmt_print(" %s%d at %s 0x%x ",
2076 ctlr
->ctlr_cname
, ctlr
->ctlr_num
,
2077 space2str(ctlr
->ctlr_space
), ctlr
->ctlr_addr
);
2078 if (ctlr
->ctlr_vec
!= 0)
2079 fmt_print("vec 0x%x ", ctlr
->ctlr_vec
);
2081 fmt_print("pri %d ", ctlr
->ctlr_prio
);
2087 * This routine prints out a message describing the given disk.
2088 * The message is identical to the one printed by the kernel during
2092 pr_diskline(disk
, num
)
2093 register struct disk_info
*disk
;
2096 struct ctlr_info
*ctlr
= disk
->disk_ctlr
;
2097 struct disk_type
*type
= disk
->disk_type
;
2099 fmt_print(" %4d. %s ", num
, disk
->disk_name
);
2100 if ((type
!= NULL
) && (disk
->label_type
== L_TYPE_SOLARIS
)) {
2101 fmt_print("<%s cyl %u alt %u hd %u sec %u>",
2102 type
->dtype_asciilabel
, type
->dtype_ncyl
,
2103 type
->dtype_acyl
, type
->dtype_nhead
,
2105 } else if ((type
!= NULL
) && (disk
->label_type
== L_TYPE_EFI
)) {
2106 cur_blksz
= disk
->disk_lbasize
;
2107 print_efi_string(type
->vendor
, type
->product
,
2108 type
->revision
, type
->capacity
);
2109 } else if (disk
->disk_flags
& DSK_RESERVED
) {
2110 fmt_print("<drive not available: reserved>");
2111 } else if (disk
->disk_flags
& DSK_UNAVAILABLE
) {
2112 fmt_print("<drive not available>");
2114 fmt_print("<drive type unknown>");
2116 if (chk_volname(disk
)) {
2118 print_volname(disk
);
2122 if (disk
->devfs_name
!= NULL
) {
2123 fmt_print(" %s\n", disk
->devfs_name
);
2125 fmt_print(" %s%d at %s%d slave %d\n",
2126 ctlr
->ctlr_dname
, disk
->disk_dkinfo
.dki_unit
,
2127 ctlr
->ctlr_cname
, ctlr
->ctlr_num
,
2128 disk
->disk_dkinfo
.dki_slave
);
2132 fmt_print(" %4d. %s at %s%d slave %d", num
, disk
->disk_name
,
2133 ctlr
->ctlr_cname
, ctlr
->ctlr_num
, disk
->disk_dkinfo
.dki_slave
);
2134 if (chk_volname(disk
)) {
2136 print_volname(disk
);
2141 " %s%d: <%s cyl %u alt %u hd %u sec %u>\n",
2142 ctlr
->ctlr_dname
, disk
->disk_dkinfo
.dki_unit
,
2143 type
->dtype_asciilabel
, type
->dtype_ncyl
,
2144 type
->dtype_acyl
, type
->dtype_nhead
,
2147 fmt_print(" %s%d: <drive type unknown>\n",
2148 ctlr
->ctlr_dname
, disk
->disk_dkinfo
.dki_unit
);
2154 * This routine prints out a given disk block number in cylinder/head/sector
2155 * format. It uses the printing routine passed in to do the actual output.
2158 pr_dblock(void (*func
)(char *, ...), diskaddr_t bn
)
2160 if (cur_label
== L_TYPE_SOLARIS
) {
2161 (*func
)("%u/%u/%u", bn2c(bn
),
2162 bn2h(bn
), bn2s(bn
));
2164 (*func
)("%llu", bn
);
2169 * This routine inputs a character from the data file. It understands
2170 * the use of '\' to prevent interpretation of a newline. It also keeps
2171 * track of the current line in the data file via a global variable.
2179 * Input the character.
2181 c
= getc(data_file
);
2183 * If it's not a backslash, return it.
2188 * It was a backslash. Get the next character.
2190 c
= getc(data_file
);
2192 * If it was a newline, update the line counter and get the next
2197 c
= getc(data_file
);
2200 * Return the character.
2206 * This routine pushes a character back onto the input pipe for the data file.
2212 (void) ungetc(c
, data_file
);
2216 * Variables to support pushing back tokens
2218 static int have_pushed_token
= 0;
2219 static TOKEN pushed_buf
;
2220 static int pushed_token
;
2223 * This routine inputs a token from the data file. A token is a series
2224 * of contiguous non-white characters or a recognized special delimiter
2225 * character. Use of the wrapper lets us always have the value of the
2226 * last token around, which is useful for error recovery.
2232 last_token_type
= sup_get_token(buf
);
2233 return (last_token_type
);
2244 * First check for presence of push-backed token.
2247 if (have_pushed_token
) {
2248 have_pushed_token
= 0;
2249 bcopy(pushed_buf
, buf
, TOKEN_SIZE
+1);
2250 return (pushed_token
);
2253 * Zero out the returned token buffer
2255 bzero(buf
, TOKEN_SIZE
+ 1);
2257 * Strip off leading white-space.
2259 while ((isspace(c
= sup_inputchar())) && (c
!= '\n'))
2262 * Read in characters until we hit unquoted white-space.
2264 for (; !isspace(c
) || quoted
; c
= sup_inputchar()) {
2266 * If we hit eof, that's a token.
2268 if (feof(data_file
))
2271 * If we hit a double quote, change the state of quoting.
2278 * If we hit a newline, that delimits a token.
2283 * If we hit any nonquoted special delimiters, that delimits
2286 if (!quoted
&& (c
== '=' || c
== ',' || c
== ':' ||
2287 c
== '#' || c
== '|' || c
== '&' || c
== '~'))
2290 * Store the character if there's room left.
2292 if (ptr
- buf
< TOKEN_SIZE
)
2296 * If we stored characters in the buffer, then we inputted a string.
2297 * Push the delimiter back into the pipe and return the string.
2299 if (ptr
- buf
> 0) {
2301 return (SUP_STRING
);
2304 * We didn't input a string, so we must have inputted a known delimiter.
2305 * store the delimiter in the buffer, so it will get returned.
2309 * Switch on the delimiter. Return the appropriate value for each one.
2328 * For comments, we flush out the rest of the line and return
2331 while ((c
= sup_inputchar()) != '\n' && !feof(data_file
))
2333 if (feof(data_file
))
2338 * Shouldn't ever get here.
2341 return (SUP_STRING
);
2349 sup_pushtoken(token_buf
, token_type
)
2354 * We can only push one token back at a time
2356 assert(have_pushed_token
== 0);
2358 have_pushed_token
= 1;
2359 bcopy(token_buf
, pushed_buf
, TOKEN_SIZE
+1);
2360 pushed_token
= token_type
;
2364 * Get an entire line of input. Handles logging, comments,
2368 get_inputline(line
, nbytes
)
2376 * Remove any leading white-space and comments
2379 while ((isspace(c
= getchar())) && (c
!= '\n'))
2381 } while (c
== COMMENT_CHAR
);
2383 * Loop on each character until end of line
2387 * If we hit eof, get out.
2393 * Add the character to the buffer.
2400 * Get the next character.
2405 * Null terminate the token.
2409 * Indicate that we've emptied the pipe
2413 * If we're running out of a file, echo the line to
2414 * the user, otherwise if we're logging, copy the
2415 * input to the log file.
2418 fmt_print("%s\n", line
);
2419 } else if (log_file
) {
2420 log_print("%s\n", line
);
2425 * execute the shell escape command
2428 execute_shell(s
, buff_size
)
2432 struct termio termio
;
2436 static char *default_shell
= "/bin/sh";
2441 shell_name
= getenv("SHELL");
2443 if (shell_name
== NULL
) {
2444 shell_name
= default_shell
;
2446 if (strlcpy(s
, shell_name
, buff_size
) >=
2448 err_print("Error: Shell command ($SHELL) too long.\n");
2453 /* save tty information */
2456 if (ioctl(0, TCGETS
, &tty
) == 0)
2459 if (ioctl(0, TCGETA
, &termio
) == 0) {
2461 tty
.c_iflag
= termio
.c_iflag
;
2462 tty
.c_oflag
= termio
.c_oflag
;
2463 tty
.c_cflag
= termio
.c_cflag
;
2464 tty
.c_lflag
= termio
.c_lflag
;
2465 for (i
= 0; i
< NCC
; i
++)
2466 tty
.c_cc
[i
] = termio
.c_cc
[i
];
2471 /* close the current file descriptor */
2472 if (cur_disk
!= NULL
) {
2473 (void) close(cur_file
);
2476 /* execute the shell escape */
2479 /* reopen file descriptor if one was open before */
2480 if (cur_disk
!= NULL
) {
2481 if ((cur_file
= open_disk(cur_disk
->disk_path
,
2482 O_RDWR
| O_NDELAY
)) < 0) {
2483 err_print("Error: can't reopen selected disk '%s'. \n",
2484 cur_disk
->disk_name
);
2489 /* Restore tty information */
2493 (void) ioctl(0, TCSETSW
, &tty
);
2494 else if (tty_flag
== 0) {
2495 termio
.c_iflag
= tty
.c_iflag
;
2496 termio
.c_oflag
= tty
.c_oflag
;
2497 termio
.c_cflag
= tty
.c_cflag
;
2498 termio
.c_lflag
= tty
.c_lflag
;
2499 for (j
= 0; j
< NCC
; j
++)
2500 termio
.c_cc
[j
] = tty
.c_cc
[j
];
2501 (void) ioctl(0, TCSETAW
, &termio
);
2505 fmt_print("\n[Hit Return to continue] \n");
2506 (void) fflush(stdin
);
2507 if (getchar() == EOF
)
2515 print_efi_string(char *vendor
, char *product
, char *revision
,
2521 char capacity_string
[10];
2525 /* Strip whitespace from the end of inquiry strings */
2526 new_vendor
= strdup(vendor
);
2527 if (new_vendor
== NULL
)
2530 for (i
= (strlen(new_vendor
) - 1); i
>= 0; i
--) {
2531 if (new_vendor
[i
] != 0x20) {
2532 new_vendor
[i
+1] = '\0';
2537 new_product
= strdup(product
);
2538 if (new_product
== NULL
) {
2543 for (i
= (strlen(new_product
) - 1); i
>= 0; i
--) {
2544 if (new_product
[i
] != 0x20) {
2545 new_product
[i
+1] = '\0';
2550 new_revision
= strdup(revision
);
2551 if (new_product
== NULL
) {
2557 for (i
= (strlen(new_revision
) - 1); i
>= 0; i
--) {
2558 if (new_revision
[i
] != 0x20) {
2559 new_revision
[i
+1] = '\0';
2564 /* Now build size string */
2565 scaled
= bn2mb(capacity
);
2566 if (scaled
>= (float)1024.0 * 1024) {
2567 (void) snprintf(capacity_string
, sizeof (capacity_string
),
2568 "%.2fTB", scaled
/((float)1024.0 * 1024));
2569 } else if (scaled
>= (float)1024.0) {
2570 (void) snprintf(capacity_string
, sizeof (capacity_string
),
2571 "%.2fGB", scaled
/(float)1024.0);
2573 (void) snprintf(capacity_string
, sizeof (capacity_string
),
2577 fmt_print("<%s-%s-%s-%s>",
2578 new_vendor
, new_product
, new_revision
, capacity_string
);