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