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