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