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