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