xref: /titanic_52/usr/src/cmd/format/io.c (revision 7aa76ffc594f84c1c092911a84f85a79ddb44c73)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file contains I/O related functions.
28  */
29 #include "global.h"
30 
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <sys/tty.h>
38 #include <sys/termio.h>
39 #include <sys/termios.h>
40 
41 #include "startup.h"
42 #include "misc.h"
43 #include "menu_partition.h"
44 #include "param.h"
45 #include "menu.h"
46 
47 
48 extern int	data_lineno;
49 extern char	*space2str();
50 extern long	strtol();
51 
52 /*
53  * This variable is used to determine whether a token is present in the pipe
54  * already.
55  */
56 static	char	token_present = 0;
57 
58 /*
59  * This variable always gives us access to the most recent token type
60  */
61 int	last_token_type = 0;
62 
63 #ifdef	__STDC__
64 /*
65  * Prototypes for ANSI C compilers
66  */
67 static int	sup_get_token(char *);
68 static void	pushchar(int c);
69 static int	checkeof(void);
70 static void	flushline(void);
71 static int	strcnt(char *s1, char *s2);
72 static int	getbn(char *str, diskaddr_t *iptr);
73 static void	print_input_choices(int type, u_ioparam_t *param);
74 static int	slist_widest_str(slist_t *slist);
75 static void	ljust_print(char *str, int width);
76 static int	sup_inputchar(void);
77 static void	sup_pushchar(int c);
78 static int	geti64(char *str, uint64_t *iptr, uint64_t *wild);
79 
80 #else	/* __STDC__ */
81 /*
82  * Prototypes for non-ANSI C compilers
83  */
84 
85 static int	sup_get_token();
86 static void	pushchar(int c);
87 static int	checkeof(void);
88 static void	flushline(void);
89 static int	strcnt(char *s1, char *s2);
90 static int	getbn(char *str, diskaddr_t *iptr);
91 static void	print_input_choices(int type, u_ioparam_t *param);
92 static int	slist_widest_str(slist_t *slist);
93 static void	ljust_print(char *str, int width);
94 static int	sup_inputchar(void);
95 static void	sup_pushchar(int c);
96 static int	geti64(char *str, uint64_t *iptr, uint64_t *wild);
97 
98 #endif	/* __STDC__ */
99 
100 
101 /*
102  * This routine pushes the given character back onto the input stream.
103  */
104 static void
105 pushchar(c)
106 	int	c;
107 {
108 	(void) ungetc(c, stdin);
109 }
110 
111 /*
112  * This routine checks the input stream for an eof condition.
113  */
114 static int
115 checkeof()
116 {
117 	return (feof(stdin));
118 }
119 
120 /*
121  * This routine gets the next token off the input stream.  A token is
122  * basically any consecutive non-white characters.
123  */
124 char *
125 gettoken(inbuf)
126 	char	*inbuf;
127 {
128 	char	*ptr = inbuf;
129 	int	c, quoted = 0;
130 
131 retoke:
132 	/*
133 	 * Remove any leading white-space.
134 	 */
135 	while ((isspace(c = getchar())) && (c != '\n'))
136 		;
137 	/*
138 	 * If we are at the beginning of a line and hit the comment character,
139 	 * flush the line and start again.
140 	 */
141 	if (!token_present && c == COMMENT_CHAR) {
142 		token_present = 1;
143 		flushline();
144 		goto retoke;
145 	}
146 	/*
147 	 * Loop on each character until we hit unquoted white-space.
148 	 */
149 	while (!isspace(c) || quoted && (c != '\n')) {
150 		/*
151 		 * If we hit eof, get out.
152 		 */
153 		if (checkeof())
154 			return (NULL);
155 		/*
156 		 * If we hit a double quote, change the state of quotedness.
157 		 */
158 		if (c == '"')
159 			quoted = !quoted;
160 		/*
161 		 * If there's room in the buffer, add the character to the end.
162 		 */
163 		else if (ptr - inbuf < TOKEN_SIZE)
164 			*ptr++ = (char)c;
165 		/*
166 		 * Get the next character.
167 		 */
168 		c = getchar();
169 	}
170 	/*
171 	 * Null terminate the token.
172 	 */
173 	*ptr = '\0';
174 	/*
175 	 * Peel off white-space still in the pipe.
176 	 */
177 	while (isspace(c) && (c != '\n'))
178 		c = getchar();
179 	/*
180 	 * If we hit another token, push it back and set state.
181 	 */
182 	if (c != '\n') {
183 		pushchar(c);
184 		token_present = 1;
185 	} else
186 		token_present = 0;
187 	/*
188 	 * Return the token.
189 	 */
190 	return (inbuf);
191 }
192 
193 /*
194  * This routine removes the leading and trailing spaces from a token.
195  */
196 void
197 clean_token(cleantoken, token)
198 	char	*cleantoken, *token;
199 {
200 	char	*ptr;
201 
202 	/*
203 	 * Strip off leading white-space.
204 	 */
205 	for (ptr = token; isspace(*ptr); ptr++)
206 		;
207 	/*
208 	 * Copy it into the clean buffer.
209 	 */
210 	(void) strcpy(cleantoken, ptr);
211 	/*
212 	 * Strip off trailing white-space.
213 	 */
214 	for (ptr = cleantoken + strlen(cleantoken) - 1;
215 		isspace(*ptr) && (ptr >= cleantoken); ptr--) {
216 		*ptr = '\0';
217 	}
218 }
219 
220 /*
221  * This routine checks if a token is already present on the input line
222  */
223 int
224 istokenpresent()
225 {
226 	return (token_present);
227 }
228 
229 /*
230  * This routine flushes the rest of an input line if there is known
231  * to be data in it.  The flush has to be qualified because the newline
232  * may have already been swallowed by the last gettoken.
233  */
234 static void
235 flushline()
236 {
237 	if (token_present) {
238 		/*
239 		 * Flush the pipe to eol or eof.
240 		 */
241 		while ((getchar() != '\n') && !checkeof())
242 			;
243 		/*
244 		 * Mark the pipe empty.
245 		 */
246 		token_present = 0;
247 	}
248 }
249 
250 /*
251  * This routine returns the number of characters that are identical
252  * between s1 and s2, stopping as soon as a mismatch is found.
253  */
254 static int
255 strcnt(s1, s2)
256 	char	*s1, *s2;
257 {
258 	int	i = 0;
259 
260 	while ((*s1 != '\0') && (*s1++ == *s2++))
261 		i++;
262 	return (i);
263 }
264 
265 /*
266  * This routine converts the given token into an integer.  The token
267  * must convert cleanly into an integer with no unknown characters.
268  * If the token is the wildcard string, and the wildcard parameter
269  * is present, the wildcard value will be returned.
270  */
271 int
272 geti(str, iptr, wild)
273 	char	*str;
274 	int	*iptr, *wild;
275 {
276 	char	*str2;
277 
278 	/*
279 	 * If there's a wildcard value and the string is wild, return the
280 	 * wildcard value.
281 	 */
282 	if (wild != NULL && strcmp(str, WILD_STRING) == 0)
283 		*iptr = *wild;
284 	else {
285 		/*
286 		 * Conver the string to an integer.
287 		 */
288 		*iptr = (int)strtol(str, &str2, 0);
289 		/*
290 		 * If any characters didn't convert, it's an error.
291 		 */
292 		if (*str2 != '\0') {
293 			err_print("`%s' is not an integer.\n", str);
294 			return (-1);
295 		}
296 	}
297 	return (0);
298 }
299 
300 /*
301  * This routine converts the given token into a long long.  The token
302  * must convert cleanly into a 64-bit integer with no unknown characters.
303  * If the token is the wildcard string, and the wildcard parameter
304  * is present, the wildcard value will be returned.
305  */
306 static int
307 geti64(str, iptr, wild)
308 	char		*str;
309 	uint64_t	*iptr, *wild;
310 {
311 	char	*str2;
312 
313 	/*
314 	 * If there's a wildcard value and the string is wild, return the
315 	 * wildcard value.
316 	 */
317 	if ((wild != NULL) && (strcmp(str, WILD_STRING)) == 0) {
318 		*iptr = *wild;
319 	} else {
320 		/*
321 		 * Conver the string to an integer.
322 		 */
323 		*iptr = (uint64_t)strtoll(str, &str2, 0);
324 		/*
325 		 * If any characters didn't convert, it's an error.
326 		 */
327 		if (*str2 != '\0') {
328 			err_print("`%s' is not an integer.\n", str);
329 			return (-1);
330 		}
331 	}
332 	return (0);
333 }
334 
335 /*
336  * This routine converts the given string into a block number on the
337  * current disk.  The format of a block number is either a self-based
338  * number, or a series of self-based numbers separated by slashes.
339  * Any number preceeding the first slash is considered a cylinder value.
340  * Any number succeeding the first slash but preceeding the second is
341  * considered a head value.  Any number succeeding the second slash is
342  * considered a sector value.  Any of these numbers can be wildcarded
343  * to the highest possible legal value.
344  */
345 static int
346 getbn(str, iptr)
347 	char	*str;
348 	diskaddr_t	*iptr;
349 {
350 	char	*cptr, *hptr, *sptr;
351 	int	cyl, head, sect;
352 	int	wild;
353 	diskaddr_t	wild64;
354 	TOKEN	buf;
355 
356 	/*
357 	 * Set cylinder pointer to beginning of string.
358 	 */
359 	cptr = str;
360 	/*
361 	 * Look for the first slash.
362 	 */
363 	while ((*str != '\0') && (*str != '/'))
364 		str++;
365 	/*
366 	 * If there wasn't one, convert string to an integer and return it.
367 	 */
368 	if (*str == '\0') {
369 		wild64 = physsects() - 1;
370 		if (geti64(cptr, iptr, &wild64))
371 			return (-1);
372 		return (0);
373 	}
374 	/*
375 	 * Null out the slash and set head pointer just beyond it.
376 	 */
377 	*str++ = '\0';
378 	hptr = str;
379 	/*
380 	 * Look for the second slash.
381 	 */
382 	while ((*str != '\0') && (*str != '/'))
383 		str++;
384 	/*
385 	 * If there wasn't one, sector pointer points to a .
386 	 */
387 	if (*str == '\0')
388 		sptr = str;
389 	/*
390 	 * If there was, null it out and set sector point just beyond it.
391 	 */
392 	else {
393 		*str++ = '\0';
394 		sptr = str;
395 	}
396 	/*
397 	 * Convert the cylinder part to an integer and store it.
398 	 */
399 	clean_token(buf, cptr);
400 	wild = ncyl + acyl - 1;
401 	if (geti(buf, &cyl, &wild))
402 		return (-1);
403 	if ((cyl < 0) || (cyl >= (ncyl + acyl))) {
404 		err_print("`%d' is out of range.\n", cyl);
405 		return (-1);
406 	}
407 	/*
408 	 * Convert the head part to an integer and store it.
409 	 */
410 	clean_token(buf, hptr);
411 	wild = nhead - 1;
412 	if (geti(buf, &head, &wild))
413 		return (-1);
414 	if ((head < 0) || (head >= nhead)) {
415 		err_print("`%d' is out of range.\n", head);
416 		return (-1);
417 	}
418 	/*
419 	 * Convert the sector part to an integer and store it.
420 	 */
421 	clean_token(buf, sptr);
422 	wild = sectors(head) - 1;
423 	if (geti(buf, &sect, &wild))
424 		return (-1);
425 	if ((sect < 0) || (sect >= sectors(head))) {
426 		err_print("`%d' is out of range.\n", sect);
427 		return (-1);
428 	}
429 	/*
430 	 * Combine the pieces into a block number and return it.
431 	 */
432 	*iptr = chs2bn(cyl, head, sect);
433 	return (0);
434 }
435 
436 /*
437  * This routine is the basis for all input into the program.  It
438  * understands the semantics of a set of input types, and provides
439  * consistent error messages for all input.  It allows for default
440  * values and prompt strings.
441  */
442 uint64_t
443 input(type, promptstr, delim, param, deflt, cmdflag)
444 	int		type;
445 	char		*promptstr;
446 	int		delim;
447 	u_ioparam_t	*param;
448 	int		*deflt;
449 	int		cmdflag;
450 {
451 	int		interactive, help, i, length, index, tied;
452 	blkaddr_t	bn;
453 	diskaddr_t	bn64;
454 	char		**str, **strings;
455 	TOKEN		token, cleantoken;
456 	TOKEN		token2, cleantoken2;
457 	char		*arg;
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 #if !defined(lint)	/* caller has aligned the pointer specifying FIO_BN */
503 			fmt_print("[%llu, ", *(diskaddr_t *)deflt);
504 			pr_dblock(fmt_print, *(diskaddr_t *)deflt);
505 			fmt_print("]");
506 #endif
507 			break;
508 		case FIO_INT:
509 			fmt_print("[%d]", *deflt);
510 			break;
511 		case FIO_INT64:
512 #if defined(lint)
513 			/* caller is longlong aligned specifying FIO_INT64 */
514 			efi_deflt = NULL;
515 #else
516 			efi_deflt = (efi_deflt_t *)deflt;
517 #endif
518 			fmt_print("[%llu]", efi_deflt->start_sector);
519 			break;
520 		case FIO_CSTR:
521 		case FIO_MSTR:
522 			strings = (char **)param->io_charlist;
523 			for (i = 0, str = strings; i < *deflt; i++, str++)
524 				;
525 			fmt_print("[%s]", *str);
526 			break;
527 		case FIO_OSTR:
528 			fmt_print("[\"%s\"]", (char *)deflt);
529 			break;
530 		case FIO_SLIST:
531 			/*
532 			 * Search for a string matching the default
533 			 * value.  If found, use it.  Otherwise
534 			 * assume the default value is actually
535 			 * an illegal choice, and default to
536 			 * the first item in the list.
537 			 */
538 			s = find_string(param->io_slist, *deflt);
539 			if (s == (char *)NULL) {
540 				s = (param->io_slist)->str;
541 			}
542 			fmt_print("[%s]", s);
543 			break;
544 		case FIO_CYL:
545 			/*
546 			 * Old-style partition size input, used to
547 			 * modify complete partition tables
548 			 */
549 			blokno = *(blkaddr32_t *)deflt;
550 			fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno,
551 			    bn2c(blokno), bn2mb(blokno), bn2gb(blokno));
552 			break;
553 		case FIO_ECYL:
554 			/*
555 			 * set up pointer to partition defaults
556 			 * structure
557 			 */
558 			part_deflt = (part_deflt_t *)deflt;
559 
560 			/*
561 			 * Build print format specifier.  We use the
562 			 * starting cylinder number which was entered
563 			 * before this call to input(), in case the
564 			 * user has changed it from the value in the
565 			 * cur_parts->pinfo_map[].dkl_cylno
566 			 * field for the current parition
567 			 */
568 
569 			/*
570 			 * Determine the proper default end cylinder:
571 			 * Start Cyl	Default Size	End Cylinder
572 			 *	0		0	0
573 			 *	>0		0	Start Cyl
574 			 *	0		>0	Default Size
575 			 *				(Cyls) - 1
576 			 *	>0		>0	(Start +
577 			 *				Default Size
578 			 *				(Cyls)) -1
579 			 */
580 
581 			if (part_deflt->deflt_size == 0) {
582 				cylno = part_deflt->start_cyl;
583 			} else if (part_deflt->start_cyl == 0) {
584 				cylno = bn2c(part_deflt->deflt_size) - 1;
585 			} else {
586 				cylno = (bn2c(part_deflt->deflt_size) +
587 					    part_deflt->start_cyl) - 1;
588 			}
589 
590 			fmt_print("[%ub, %uc, %de, %1.2fmb, %1.2fgb]",
591 			    part_deflt->deflt_size,
592 			    bn2c(part_deflt->deflt_size),
593 			    cylno,
594 			    bn2mb(part_deflt->deflt_size),
595 			    bn2gb(part_deflt->deflt_size));
596 
597 			break;
598 		case FIO_EFI:
599 #if defined(lint)
600 			/* caller is longlong aligned when specifying FIO_EFI */
601 			efi_deflt = NULL;
602 #else
603 			efi_deflt = (efi_deflt_t *)deflt;
604 #endif
605 
606 			fmt_print("[%llub, %llue, %llumb, %llugb, %llutb]",
607 			    efi_deflt->end_sector,
608 			    efi_deflt->start_sector + efi_deflt->end_sector - 1,
609 			    (efi_deflt->end_sector * cur_blksz) /
610 				(1024 * 1024),
611 			    (efi_deflt->end_sector * cur_blksz) /
612 				(1024 * 1024 * 1024),
613 			    (efi_deflt->end_sector * cur_blksz) /
614 				((uint64_t)1024 * 1024 * 1024 * 1024));
615 			break;
616 		case FIO_OPINT:
617 			/* no default value for optional input type */
618 			fmt_print("[default]");
619 			break;
620 		default:
621 			err_print("Error: unknown input type.\n");
622 			fullabort();
623 		}
624 	}
625 	/*
626 	 * Print the delimiter character.
627 	 */
628 	fmt_print("%c ", delim);
629 	/*
630 	 * Get the token.  If we hit eof, exit the program gracefully.
631 	 */
632 	if (gettoken(token) == NULL)
633 		fullabort();
634 
635 	/*
636 	 * check if the user has issued (!) , escape to shell
637 	 */
638 	if ((cmdflag == CMD_INPUT) && (token[0] == '!')) {
639 
640 	    /* get the list of arguments to shell command */
641 		(void) memset(shell_argv, 0, sizeof (shell_argv));
642 
643 		/* initialize to the first token... */
644 		arg = &token[1];
645 
646 		/*
647 		 * ... and then collect all tokens until the end of
648 		 * the line as arguments
649 		 */
650 		do {
651 			/* skip empty tokens. */
652 			if (*arg == '\0')
653 				continue;
654 			/*
655 			 * If either of the following two strlcat()
656 			 * operations overflows, report an error and
657 			 * exit gracefully.
658 			 */
659 			if ((strlcat(shell_argv, arg, sizeof (shell_argv)) >=
660 				sizeof (shell_argv)) ||
661 			    (strlcat(shell_argv, " ", sizeof (shell_argv)) >=
662 				sizeof (shell_argv))) {
663 				err_print("Error: Command line too long.\n");
664 				fullabort();
665 			}
666 		} while (token_present && (arg = gettoken(token)) != NULL);
667 
668 		/* execute the shell command */
669 		(void) execute_shell(shell_argv, sizeof (shell_argv));
670 		redisplay_menu_list((char **)param->io_charlist);
671 		if (interactive) {
672 			goto reprompt;
673 		}
674 	}
675 
676 	/*
677 	 * Certain commands accept up to two tokens
678 	 * Unfortunately, this is kind of a hack.
679 	 */
680 	token2[0] = 0;
681 	cleantoken2[0] = 0;
682 	if (type == FIO_CYL || type == FIO_ECYL) {
683 		if (token_present) {
684 			if (gettoken(token2) == NULL)
685 				fullabort();
686 			clean_token(cleantoken2, token2);
687 		}
688 	}
689 	/*
690 	 * Echo the token back to the user if it was in the pipe or we
691 	 * are running out of a command file.
692 	 */
693 	if (!interactive || option_f) {
694 		if (token2[0] == 0) {
695 			fmt_print("%s\n", token);
696 		} else {
697 			fmt_print("%s %s\n", token, token2);
698 		}
699 	}
700 	/*
701 	 * If we are logging, echo the token to the log file.  The else
702 	 * is necessary here because the above printf will also put the
703 	 * token in the log file.
704 	 */
705 	else if (log_file) {
706 		log_print("%s %s\n", token, token2);
707 	}
708 	/*
709 	 * If the token was not in the pipe and it wasn't a command, flush
710 	 * the rest of the line to keep things in sync.
711 	 */
712 	if (interactive && cmdflag != CMD_INPUT)
713 		flushline();
714 	/*
715 	 * Scrub off the white-space.
716 	 */
717 	clean_token(cleantoken, token);
718 	/*
719 	 * If the input was a blank line and we weren't prompting
720 	 * specifically for a blank line...
721 	 */
722 	if ((strcmp(cleantoken, "") == 0) && (type != FIO_BLNK)) {
723 		/*
724 		 * If there's a default, return it.
725 		 */
726 		if (deflt != NULL) {
727 			if (type == FIO_OSTR) {
728 				/*
729 				 * Duplicate and return the default string
730 				 */
731 				return ((int)alloc_string((char *)deflt));
732 			} else if (type == FIO_SLIST) {
733 				/*
734 				 * If we can find a match for the default
735 				 * value in the list, return the default
736 				 * value.  If there's no match for the
737 				 * default value, it's an illegal
738 				 * choice.  Return the first value in
739 				 * the list.
740 				 */
741 				s = find_string(param->io_slist, *deflt);
742 				if ((cur_label == L_TYPE_EFI) &&
743 				    (s == (char *)NULL)) {
744 					return (*deflt);
745 				}
746 				if (s == (char *)NULL) {
747 					return ((param->io_slist)->value);
748 				} else {
749 					return (*deflt);
750 				}
751 			} else if (type == FIO_OPINT) {
752 				/*
753 				 * The user didn't enter anything
754 				 */
755 				return (0);
756 			} else if (type == FIO_ECYL) {
757 				return (part_deflt->deflt_size);
758 			} else if (type == FIO_INT64) {
759 				return (efi_deflt->start_sector);
760 			} else if (type == FIO_EFI) {
761 				return (efi_deflt->end_sector);
762 			} else {
763 				return (*deflt);
764 			}
765 		}
766 		/*
767 		 * If the blank was not in the pipe, just reprompt.
768 		 */
769 		if (interactive) {
770 			goto reprompt;
771 		}
772 		/*
773 		 * If the blank was in the pipe, it's an error.
774 		 */
775 		err_print("No default for this entry.\n");
776 		cmdabort(SIGINT);
777 	}
778 	/*
779 	 * If token is a '?' or a 'h', it is a request for help.
780 	 */
781 	if ((strcmp(cleantoken, "?") == 0) ||
782 		(strcmp(cleantoken, "h") == 0) ||
783 			(strcmp(cleantoken, "help") == 0)) {
784 		help = 1;
785 	}
786 	/*
787 	 * Switch on the type of input expected.
788 	 */
789 	switch (type) {
790 	/*
791 	 * Expecting a disk block number.
792 	 */
793 	case FIO_BN:
794 		/*
795 		 * Parameter is the bounds of legal block numbers.
796 		 */
797 		bounds = (struct bounds *)&param->io_bounds;
798 		/*
799 		 * Print help message if required.
800 		 */
801 		if (help) {
802 			fmt_print("Expecting a block number from %llu (",
803 			    bounds->lower);
804 			pr_dblock(fmt_print, bounds->lower);
805 			fmt_print(") to %llu (", bounds->upper);
806 			pr_dblock(fmt_print, bounds->upper);
807 			fmt_print(")\n");
808 			break;
809 		}
810 		/*
811 		 * Convert token to a disk block number.
812 		 */
813 		if (cur_label == L_TYPE_EFI) {
814 		    if (geti64(cleantoken, (uint64_t *)&bn64,
815 			(uint64_t *)NULL))
816 			    break;
817 		} else {
818 		    if (getbn(cleantoken, &bn64))
819 			break;
820 		}
821 		/*
822 		 * Check to be sure it is within the legal bounds.
823 		 */
824 		if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
825 			err_print("`");
826 			pr_dblock(err_print, bn64);
827 			err_print("' is out of range.\n");
828 			break;
829 		}
830 		/*
831 		 * It's ok, return it.
832 		 */
833 		return (bn64);
834 	/*
835 	 * Expecting an integer.
836 	 */
837 	case FIO_INT:
838 		/*
839 		 * Parameter is the bounds of legal integers.
840 		 */
841 		bounds = (struct bounds *)&param->io_bounds;
842 		/*
843 		 * Print help message if required.
844 		 */
845 		if (help) {
846 			fmt_print("Expecting an integer from %llu",
847 			    bounds->lower);
848 			fmt_print(" to %llu\n", bounds->upper);
849 			break;
850 		}
851 		/*
852 		 * Convert the token into an integer.
853 		 */
854 		if (geti(cleantoken, (int *)&bn, (int *)NULL))
855 			break;
856 		/*
857 		 * Check to be sure it is within the legal bounds.
858 		 */
859 		if ((bn < bounds->lower) || (bn > bounds->upper)) {
860 			err_print("`%lu' is out of range.\n", bn);
861 			break;
862 		}
863 		/*
864 		 * If it's ok, return it.
865 		 */
866 		return (bn);
867 	case FIO_INT64:
868 		/*
869 		 * Parameter is the bounds of legal integers.
870 		 */
871 		bounds = (struct bounds *)&param->io_bounds;
872 		/*
873 		 * Print help message if required.
874 		 */
875 		if (help) {
876 			fmt_print("Expecting an integer from %llu",
877 			    bounds->lower);
878 			fmt_print(" to %llu\n", bounds->upper);
879 			break;
880 		}
881 		/*
882 		 * Convert the token into an integer.
883 		 */
884 		if (geti64(cleantoken, (uint64_t *)&bn64, (uint64_t *)NULL)) {
885 			break;
886 		}
887 		/*
888 		 * Check to be sure it is within the legal bounds.
889 		 */
890 		if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
891 			err_print("`%llu' is out of range.\n", bn64);
892 			break;
893 		}
894 		/*
895 		 * If it's ok, return it.
896 		 */
897 		return (bn64);
898 	/*
899 	 * Expecting an integer, or no input.
900 	 */
901 	case FIO_OPINT:
902 		/*
903 		 * Parameter is the bounds of legal integers.
904 		 */
905 		bounds = (struct bounds *)&param->io_bounds;
906 		/*
907 		 * Print help message if required.
908 		 */
909 		if (help) {
910 			fmt_print("Expecting an integer from %llu",
911 			    bounds->lower);
912 			fmt_print(" to %llu, or no input\n", bounds->upper);
913 			break;
914 		}
915 		/*
916 		 * Convert the token into an integer.
917 		 */
918 		if (geti(cleantoken, (int *)&bn, (int *)NULL))
919 			break;
920 		/*
921 		 * Check to be sure it is within the legal bounds.
922 		 */
923 		if ((bn < bounds->lower) || (bn > bounds->upper)) {
924 			err_print("`%lu' is out of range.\n", bn);
925 			break;
926 		}
927 		/*
928 		 * For optional case, return 1 indicating that
929 		 * the user actually did enter something.
930 		 */
931 		if (!deflt)
932 			*deflt = bn;
933 		return (1);
934 	/*
935 	 * Expecting a closed string.  This means that the input
936 	 * string must exactly match one of the strings passed in
937 	 * as the parameter.
938 	 */
939 	case FIO_CSTR:
940 		/*
941 		 * The parameter is a null terminated array of character
942 		 * pointers, each one pointing to a legal input string.
943 		 */
944 		strings = (char **)param->io_charlist;
945 		/*
946 		 * Walk through the legal strings, seeing if any of them
947 		 * match the token.  If a match is made, return the index
948 		 * of the string that was matched.
949 		 */
950 		for (str = strings; *str != NULL; str++)
951 			if (strcmp(cleantoken, *str) == 0)
952 				return (str - strings);
953 		/*
954 		 * Print help message if required.
955 		 */
956 		if (help) {
957 			print_input_choices(type, param);
958 		} else {
959 			err_print("`%s' is not expected.\n", cleantoken);
960 		}
961 		break;
962 	/*
963 	 * Expecting a matched string.  This means that the input
964 	 * string must either match one of the strings passed in,
965 	 * or be a unique abbreviation of one of them.
966 	 */
967 	case FIO_MSTR:
968 		/*
969 		 * The parameter is a null terminated array of character
970 		 * pointers, each one pointing to a legal input string.
971 		 */
972 		strings = (char **)param->io_charlist;
973 		length = index = tied = 0;
974 		/*
975 		 * Loop through the legal input strings.
976 		 */
977 		for (str = strings; *str != NULL; str++) {
978 			/*
979 			 * See how many characters of the token match
980 			 * this legal string.
981 			 */
982 			i = strcnt(cleantoken, *str);
983 			/*
984 			 * If it's not the whole token, then it's not a match.
985 			 */
986 			if ((uint_t)i < strlen(cleantoken))
987 				continue;
988 			/*
989 			 * If it ties with another input, remember that.
990 			 */
991 			if (i == length)
992 				tied = 1;
993 			/*
994 			 * If it matches the most so far, record that.
995 			 */
996 			if (i > length) {
997 				index = str - strings;
998 				tied = 0;
999 				length = i;
1000 			}
1001 		}
1002 		/*
1003 		 * Print help message if required.
1004 		 */
1005 		if (length == 0) {
1006 			if (help) {
1007 				print_input_choices(type, param);
1008 			} else {
1009 				err_print("`%s' is not expected.\n",
1010 				    cleantoken);
1011 			}
1012 			break;
1013 		}
1014 		/*
1015 		 * If the abbreviation was non-unique, it's an error.
1016 		 */
1017 		if (tied) {
1018 			err_print("`%s' is ambiguous.\n", cleantoken);
1019 			break;
1020 		}
1021 		/*
1022 		 * We matched one.  Return the index of the string we matched.
1023 		 */
1024 		return (index);
1025 	/*
1026 	 * Expecting an open string.  This means that any string is legal.
1027 	 */
1028 	case FIO_OSTR:
1029 		/*
1030 		 * Print a help message if required.
1031 		 */
1032 		if (help) {
1033 			fmt_print("Expecting a string\n");
1034 			break;
1035 		}
1036 		/*
1037 		 * alloc a copy of the string and return it
1038 		 */
1039 		return ((int)alloc_string(token));
1040 
1041 	/*
1042 	 * Expecting a blank line.
1043 	 */
1044 	case FIO_BLNK:
1045 		/*
1046 		 * We are always in non-echo mode when we are inputting
1047 		 * this type.  We echo the newline as a carriage return
1048 		 * only so the prompt string will be covered over.
1049 		 */
1050 		nolog_print("\015");
1051 		/*
1052 		 * If we are logging, send a newline to the log file.
1053 		 */
1054 		if (log_file)
1055 			log_print("\n");
1056 		/*
1057 		 * There is no value returned for this type.
1058 		 */
1059 		return (0);
1060 
1061 	/*
1062 	 * Expecting one of the entries in a string list.
1063 	 * Accept unique abbreviations.
1064 	 * Return the value associated with the matched string.
1065 	 */
1066 	case FIO_SLIST:
1067 		i = find_value((slist_t *)param->io_slist,
1068 			cleantoken, &value);
1069 		if (i == 1) {
1070 			return (value);
1071 		} else {
1072 			/*
1073 			 * Print help message if required.
1074 			 */
1075 
1076 			if (help) {
1077 				print_input_choices(type, param);
1078 			} else {
1079 				if (i == 0)
1080 					err_print("`%s' not expected.\n",
1081 					    cleantoken);
1082 				else
1083 					err_print("`%s' is ambiguous.\n",
1084 					    cleantoken);
1085 			}
1086 		}
1087 		break;
1088 
1089 	/*
1090 	 * Cylinder size input when modifying a complete partition map
1091 	 */
1092 	case FIO_CYL:
1093 		/*
1094 		 * Parameter is the bounds of legal block numbers.
1095 		 */
1096 		bounds = (struct bounds *)&param->io_bounds;
1097 		assert(bounds->lower == 0);
1098 		/*
1099 		 * Print help message if required.
1100 		 */
1101 		if (help) {
1102 			fmt_print("Expecting up to %llu blocks,",
1103 			    bounds->upper);
1104 			fmt_print(" %u cylinders, ", bn2c(bounds->upper));
1105 			fmt_print(" %1.2f megabytes, ", bn2mb(bounds->upper));
1106 			fmt_print("or %1.2f gigabytes\n", bn2gb(bounds->upper));
1107 			break;
1108 		}
1109 		/*
1110 		 * Parse the first token: try to find 'b', 'c' or 'm'
1111 		 */
1112 		s = cleantoken;
1113 		while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
1114 			s++;
1115 		}
1116 		/*
1117 		 * If we found a conversion specifier, second token is unused
1118 		 * Otherwise, the second token should supply it.
1119 		 */
1120 		if (*s != 0) {
1121 			value = *s;
1122 			*s = 0;
1123 		} else {
1124 			value = cleantoken2[0];
1125 		}
1126 		/*
1127 		 * If the token is the wild card, simply supply the max
1128 		 * This order allows the user to specify the maximum in
1129 		 * either blocks/cyls/megabytes - a convenient fiction.
1130 		 */
1131 		if (strcmp(cleantoken, WILD_STRING) == 0) {
1132 			return (bounds->upper);
1133 		}
1134 		/*
1135 		 * Allow the user to specify zero with no units,
1136 		 * by just defaulting to cylinders.
1137 		 */
1138 		if (strcmp(cleantoken, "0") == 0) {
1139 			value = 'c';
1140 		}
1141 		/*
1142 		 * If there's a decimal point, but no unit specification,
1143 		 * let's assume megabytes.
1144 		 */
1145 		if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
1146 			value = 'm';
1147 		}
1148 		/*
1149 		 * Handle each unit type we support
1150 		 */
1151 		switch (value) {
1152 		case 'b':
1153 			/*
1154 			 * Convert token to a disk block number.
1155 			 */
1156 			if (geti64(cleantoken, &bn64, &bounds->upper))
1157 				break;
1158 			/*
1159 			 * Check to be sure it is within the legal bounds.
1160 			 */
1161 			if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
1162 				err_print(
1163 				    "`%llub' is out of the range %llu "
1164 				    "to %llu\n",
1165 				    bn64, bounds->lower, bounds->upper);
1166 				break;
1167 			}
1168 			/*
1169 			 * Verify the block lies on a cylinder boundary
1170 			 */
1171 			if ((bn64 % spc()) != 0) {
1172 				err_print(
1173 				    "partition size must be a multiple of "
1174 				    "%u blocks to lie on a cylinder boundary\n",
1175 				    spc());
1176 				err_print(
1177 				    "%llu blocks is approximately %u cylinders,"
1178 				    " %1.2f megabytes or %1.2f gigabytes\n",
1179 				    bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
1180 				break;
1181 			}
1182 			return (bn64);
1183 		case 'c':
1184 			/*
1185 			 * Convert token from a number of cylinders to
1186 			 * a number of blocks.
1187 			 */
1188 			i = bn2c(bounds->upper);
1189 			if (geti(cleantoken, &cyls, &i))
1190 				break;
1191 			/*
1192 			 * Check the bounds - cyls is number of cylinders
1193 			 */
1194 			if (cyls > (bounds->upper/spc())) {
1195 				err_print("`%dc' is out of range\n", cyls);
1196 				break;
1197 			}
1198 			/*
1199 			 * Convert cylinders to blocks and return
1200 			 */
1201 			return (cyls * spc());
1202 		case 'm':
1203 			/*
1204 			 * Convert token from megabytes to a block number.
1205 			 */
1206 			if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
1207 				err_print("`%s' is not recognized\n",
1208 				    cleantoken);
1209 				break;
1210 			}
1211 			/*
1212 			 * Check the bounds
1213 			 */
1214 			if (nmegs > bn2mb(bounds->upper)) {
1215 				err_print("`%1.2fmb' is out of range\n", nmegs);
1216 				break;
1217 			}
1218 			/*
1219 			 * Convert to blocks
1220 			 */
1221 			bn64 = mb2bn(nmegs);
1222 			/*
1223 			 * Round value up to nearest cylinder
1224 			 */
1225 			i = spc();
1226 			bn64 = ((bn64 + (i-1)) / i) * i;
1227 			return (bn64);
1228 		case 'g':
1229 			/*
1230 			 * Convert token from gigabytes to a block number.
1231 			 */
1232 			if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
1233 				err_print("`%s' is not recognized\n",
1234 				    cleantoken);
1235 				break;
1236 			}
1237 			/*
1238 			 * Check the bounds
1239 			 */
1240 			if (ngigs > bn2gb(bounds->upper)) {
1241 				err_print("`%1.2fgb' is out of range\n", ngigs);
1242 				break;
1243 			}
1244 			/*
1245 			 * Convert to blocks
1246 			 */
1247 			bn64 = gb2bn(ngigs);
1248 			/*
1249 			 * Round value up to nearest cylinder
1250 			 */
1251 			i = spc();
1252 			bn64 = ((bn64 + (i-1)) / i) * i;
1253 			return (bn64);
1254 		default:
1255 			err_print(
1256 "Please specify units in either b(blocks), c(cylinders), m(megabytes) \
1257 or g(gigabytes)\n");
1258 			break;
1259 		}
1260 		break;
1261 
1262 	case FIO_ECYL:
1263 		/*
1264 		 * Parameter is the bounds of legal block numbers.
1265 		 */
1266 		bounds = (struct bounds *)&param->io_bounds;
1267 		assert(bounds->lower == 0);
1268 
1269 		/*
1270 		 * Print help message if required.
1271 		 */
1272 		if (help) {
1273 			fmt_print("Expecting up to %llu blocks,",
1274 			    bounds->upper);
1275 			fmt_print(" %u cylinders, ",
1276 			    bn2c(bounds->upper));
1277 			fmt_print(" %u end cylinder, ",
1278 			    (uint_t)(bounds->upper / spc()));
1279 			fmt_print(" %1.2f megabytes, ",
1280 			    bn2mb(bounds->upper));
1281 			fmt_print("or %1.2f gigabytes\n",
1282 			    bn2gb(bounds->upper));
1283 			break;
1284 		}
1285 
1286 		/*
1287 		 * Parse the first token: try to find 'b', 'c', 'e'
1288 		 * or 'm'
1289 		 */
1290 		s = cleantoken;
1291 		while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
1292 			s++;
1293 		}
1294 
1295 		/*
1296 		 * If we found a conversion specifier, second token is
1297 		 * unused Otherwise, the second token should supply it.
1298 		 */
1299 		if (*s != 0) {
1300 			value = *s;
1301 			*s = 0;
1302 		} else {
1303 			value = cleantoken2[0];
1304 		}
1305 
1306 		/*
1307 		 * If the token is the wild card, simply supply the max
1308 		 * This order allows the user to specify the maximum in
1309 		 * either blocks/cyls/megabytes - a convenient fiction.
1310 		 */
1311 		if (strcmp(cleantoken, WILD_STRING) == 0) {
1312 			return (bounds->upper);
1313 		}
1314 
1315 		/*
1316 		 * Allow the user to specify zero with no units,
1317 		 * by just defaulting to cylinders.
1318 		 */
1319 
1320 		if (value != 'e' && strcmp(cleantoken, "0") == 0) {
1321 			value = 'c';
1322 		}
1323 
1324 
1325 		/*
1326 		 * If there's a decimal point, but no unit
1327 		 * specification, let's assume megabytes.
1328 		 */
1329 		if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
1330 			value = 'm';
1331 		}
1332 
1333 		/*
1334 		 * Handle each unit type we support
1335 		 */
1336 		switch (value) {
1337 		case 'b':
1338 			/*
1339 			 * Convert token to a disk block number.
1340 			 */
1341 			if (geti64(cleantoken, &bn64, &bounds->upper))
1342 				break;
1343 			/*
1344 			 * Check to be sure it is within the
1345 			 * legal bounds.
1346 			 */
1347 			if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
1348 				err_print(
1349 "`%llub' is out of the range %llu to %llu\n",
1350 				    bn64, bounds->lower, bounds->upper);
1351 				break;
1352 			}
1353 
1354 			/*
1355 			 * Verify the block lies on a cylinder
1356 			 * boundary
1357 			 */
1358 			if ((bn64 % spc()) != 0) {
1359 				err_print(
1360 				    "partition size must be a multiple of %u "
1361 				    "blocks to lie on a cylinder boundary\n",
1362 				    spc());
1363 				err_print(
1364 				    "%llu blocks is approximately %u cylinders,"
1365 				    " %1.2f megabytes or %1.2f gigabytes\n",
1366 				    bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
1367 				break;
1368 			}
1369 
1370 			return (bn64);
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 %u\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) != 1) {
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 			bn64 = mb2bn(nmegs);
1462 
1463 			/*
1464 			 * Round value up to nearest cylinder
1465 			 */
1466 			i = spc();
1467 			bn64 = ((bn64 + (i-1)) / i) * i;
1468 			return (bn64);
1469 
1470 		case 'g':
1471 			/*
1472 			 * Convert token from gigabytes to a
1473 			 * block number.
1474 			 */
1475 			if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
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 			bn64 = gb2bn(ngigs);
1493 
1494 			/*
1495 			 * Round value up to nearest cylinder
1496 			 */
1497 			i = spc();
1498 			bn64 = ((bn64 + (i-1)) / i) * i;
1499 			return (bn64);
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 * cur_blksz)/
1522 				(1024 * 1024));
1523 			fmt_print("or %llu gigabytes\n",
1524 			    (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
1525 				(1024 * 1024 * 1024));
1526 			fmt_print("or %llu terabytes\n",
1527 			    (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
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) != 1) {
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) != 1) {
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) != 1) {
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 / cur_blksz);
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 %u alt %u hd %u sec %u>",
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 		cur_blksz = disk->disk_lbasize;
2106 		print_efi_string(type->vendor, type->product,
2107 			type->revision, type->capacity);
2108 	} else if (disk->disk_flags & DSK_RESERVED) {
2109 		fmt_print("<drive not available: reserved>");
2110 	} else if (disk->disk_flags & DSK_UNAVAILABLE) {
2111 		fmt_print("<drive not available>");
2112 	} else {
2113 		fmt_print("<drive type unknown>");
2114 	}
2115 	if (chk_volname(disk)) {
2116 		fmt_print("  ");
2117 		print_volname(disk);
2118 	}
2119 	fmt_print("\n");
2120 
2121 	if (disk->devfs_name != NULL) {
2122 		fmt_print("          %s\n", disk->devfs_name);
2123 	} else {
2124 		fmt_print("          %s%d at %s%d slave %d\n",
2125 			ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
2126 			ctlr->ctlr_cname, ctlr->ctlr_num,
2127 			disk->disk_dkinfo.dki_slave);
2128 	}
2129 
2130 #ifdef	OLD
2131 	fmt_print("    %4d. %s at %s%d slave %d", num, disk->disk_name,
2132 	    ctlr->ctlr_cname, ctlr->ctlr_num, disk->disk_dkinfo.dki_slave);
2133 	if (chk_volname(disk)) {
2134 		fmt_print(": ");
2135 		print_volname(disk);
2136 	}
2137 	fmt_print("\n");
2138 	if (type != NULL) {
2139 		fmt_print(
2140 "           %s%d: <%s cyl %u alt %u hd %u sec %u>\n",
2141 		    ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
2142 		    type->dtype_asciilabel, type->dtype_ncyl,
2143 		    type->dtype_acyl, type->dtype_nhead,
2144 		    type->dtype_nsect);
2145 	} else {
2146 		fmt_print("           %s%d: <drive type unknown>\n",
2147 		    ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit);
2148 	}
2149 #endif /* OLD */
2150 }
2151 
2152 /*
2153  * This routine prints out a given disk block number in cylinder/head/sector
2154  * format.  It uses the printing routine passed in to do the actual output.
2155  */
2156 void
2157 pr_dblock(void (*func)(char *, ...), diskaddr_t bn)
2158 {
2159 	if (cur_label == L_TYPE_SOLARIS) {
2160 		(*func)("%u/%u/%u", bn2c(bn),
2161 		    bn2h(bn), bn2s(bn));
2162 	} else {
2163 		(*func)("%llu", bn);
2164 	}
2165 }
2166 
2167 /*
2168  * This routine inputs a character from the data file.  It understands
2169  * the use of '\' to prevent interpretation of a newline.  It also keeps
2170  * track of the current line in the data file via a global variable.
2171  */
2172 static int
2173 sup_inputchar()
2174 {
2175 	int	c;
2176 
2177 	/*
2178 	 * Input the character.
2179 	 */
2180 	c = getc(data_file);
2181 	/*
2182 	 * If it's not a backslash, return it.
2183 	 */
2184 	if (c != '\\')
2185 		return (c);
2186 	/*
2187 	 * It was a backslash.  Get the next character.
2188 	 */
2189 	c = getc(data_file);
2190 	/*
2191 	 * If it was a newline, update the line counter and get the next
2192 	 * character.
2193 	 */
2194 	if (c == '\n') {
2195 		data_lineno++;
2196 		c = getc(data_file);
2197 	}
2198 	/*
2199 	 * Return the character.
2200 	 */
2201 	return (c);
2202 }
2203 
2204 /*
2205  * This routine pushes a character back onto the input pipe for the data file.
2206  */
2207 static void
2208 sup_pushchar(c)
2209 	int	c;
2210 {
2211 	(void) ungetc(c, data_file);
2212 }
2213 
2214 /*
2215  * Variables to support pushing back tokens
2216  */
2217 static  int	have_pushed_token = 0;
2218 static  TOKEN	pushed_buf;
2219 static  int	pushed_token;
2220 
2221 /*
2222  * This routine inputs a token from the data file.  A token is a series
2223  * of contiguous non-white characters or a recognized special delimiter
2224  * character.  Use of the wrapper lets us always have the value of the
2225  * last token around, which is useful for error recovery.
2226  */
2227 int
2228 sup_gettoken(buf)
2229 	char	*buf;
2230 {
2231 	last_token_type = sup_get_token(buf);
2232 	return (last_token_type);
2233 }
2234 
2235 static int
2236 sup_get_token(buf)
2237 	char	*buf;
2238 {
2239 	char	*ptr = buf;
2240 	int	c, quoted = 0;
2241 
2242 	/*
2243 	 * First check for presence of push-backed token.
2244 	 * If so, return it.
2245 	 */
2246 	if (have_pushed_token) {
2247 		have_pushed_token = 0;
2248 		bcopy(pushed_buf, buf, TOKEN_SIZE+1);
2249 		return (pushed_token);
2250 	}
2251 	/*
2252 	 * Zero out the returned token buffer
2253 	 */
2254 	bzero(buf, TOKEN_SIZE + 1);
2255 	/*
2256 	 * Strip off leading white-space.
2257 	 */
2258 	while ((isspace(c = sup_inputchar())) && (c != '\n'))
2259 		;
2260 	/*
2261 	 * Read in characters until we hit unquoted white-space.
2262 	 */
2263 	for (; !isspace(c) || quoted; c = sup_inputchar()) {
2264 		/*
2265 		 * If we hit eof, that's a token.
2266 		 */
2267 		if (feof(data_file))
2268 			return (SUP_EOF);
2269 		/*
2270 		 * If we hit a double quote, change the state of quoting.
2271 		 */
2272 		if (c == '"') {
2273 			quoted = !quoted;
2274 			continue;
2275 		}
2276 		/*
2277 		 * If we hit a newline, that delimits a token.
2278 		 */
2279 		if (c == '\n')
2280 			break;
2281 		/*
2282 		 * If we hit any nonquoted special delimiters, that delimits
2283 		 * a token.
2284 		 */
2285 		if (!quoted && (c == '=' || c == ',' || c == ':' ||
2286 			c == '#' || c == '|' || c == '&' || c == '~'))
2287 			break;
2288 		/*
2289 		 * Store the character if there's room left.
2290 		 */
2291 		if (ptr - buf < TOKEN_SIZE)
2292 			*ptr++ = (char)c;
2293 	}
2294 	/*
2295 	 * If we stored characters in the buffer, then we inputted a string.
2296 	 * Push the delimiter back into the pipe and return the string.
2297 	 */
2298 	if (ptr - buf > 0) {
2299 		sup_pushchar(c);
2300 		return (SUP_STRING);
2301 	}
2302 	/*
2303 	 * We didn't input a string, so we must have inputted a known delimiter.
2304 	 * store the delimiter in the buffer, so it will get returned.
2305 	 */
2306 	buf[0] = c;
2307 	/*
2308 	 * Switch on the delimiter.  Return the appropriate value for each one.
2309 	 */
2310 	switch (c) {
2311 	case '=':
2312 		return (SUP_EQL);
2313 	case ':':
2314 		return (SUP_COLON);
2315 	case ',':
2316 		return (SUP_COMMA);
2317 	case '\n':
2318 		return (SUP_EOL);
2319 	case '|':
2320 		return (SUP_OR);
2321 	case '&':
2322 		return (SUP_AND);
2323 	case '~':
2324 		return (SUP_TILDE);
2325 	case '#':
2326 		/*
2327 		 * For comments, we flush out the rest of the line and return
2328 		 * an EOL.
2329 		 */
2330 		while ((c = sup_inputchar()) != '\n' && !feof(data_file))
2331 			;
2332 		if (feof(data_file))
2333 			return (SUP_EOF);
2334 		else
2335 			return (SUP_EOL);
2336 	/*
2337 	 * Shouldn't ever get here.
2338 	 */
2339 	default:
2340 		return (SUP_STRING);
2341 	}
2342 }
2343 
2344 /*
2345  * Push back a token
2346  */
2347 void
2348 sup_pushtoken(token_buf, token_type)
2349 	char	*token_buf;
2350 	int	token_type;
2351 {
2352 	/*
2353 	 * We can only push one token back at a time
2354 	 */
2355 	assert(have_pushed_token == 0);
2356 
2357 	have_pushed_token = 1;
2358 	bcopy(token_buf, pushed_buf, TOKEN_SIZE+1);
2359 	pushed_token = token_type;
2360 }
2361 
2362 /*
2363  * Get an entire line of input.  Handles logging, comments,
2364  * and EOF.
2365  */
2366 void
2367 get_inputline(line, nbytes)
2368 	char	*line;
2369 	int	nbytes;
2370 {
2371 	char	*p = line;
2372 	int	c;
2373 
2374 	/*
2375 	 * Remove any leading white-space and comments
2376 	 */
2377 	do {
2378 		while ((isspace(c = getchar())) && (c != '\n'))
2379 			;
2380 	} while (c == COMMENT_CHAR);
2381 	/*
2382 	 * Loop on each character until end of line
2383 	 */
2384 	while (c != '\n') {
2385 		/*
2386 		 * If we hit eof, get out.
2387 		 */
2388 		if (checkeof()) {
2389 			fullabort();
2390 		}
2391 		/*
2392 		 * Add the character to the buffer.
2393 		 */
2394 		if (nbytes > 1) {
2395 			*p++ = (char)c;
2396 			nbytes --;
2397 		}
2398 		/*
2399 		 * Get the next character.
2400 		 */
2401 		c = getchar();
2402 	}
2403 	/*
2404 	 * Null terminate the token.
2405 	 */
2406 	*p = 0;
2407 	/*
2408 	 * Indicate that we've emptied the pipe
2409 	 */
2410 	token_present = 0;
2411 	/*
2412 	 * If we're running out of a file, echo the line to
2413 	 * the user, otherwise if we're logging, copy the
2414 	 * input to the log file.
2415 	 */
2416 	if (option_f) {
2417 		fmt_print("%s\n", line);
2418 	} else if (log_file) {
2419 		log_print("%s\n", line);
2420 	}
2421 }
2422 
2423 /*
2424  * execute the shell escape command
2425  */
2426 int
2427 execute_shell(s, buff_size)
2428 	char	*s;
2429 	size_t	buff_size;
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 		if (strlcpy(s, shell_name, buff_size) >=
2446 		    buff_size) {
2447 			err_print("Error: Shell command ($SHELL) too long.\n");
2448 			fullabort();
2449 		}
2450 	}
2451 
2452 	/* save tty information */
2453 
2454 	if (isatty(0)) {
2455 		if (ioctl(0, TCGETS, &tty) == 0)
2456 			tty_flag = 1;
2457 		else {
2458 			if (ioctl(0, TCGETA, &termio) == 0) {
2459 				tty_flag = 0;
2460 				tty.c_iflag = termio.c_iflag;
2461 				tty.c_oflag = termio.c_oflag;
2462 				tty.c_cflag = termio.c_cflag;
2463 				tty.c_lflag = termio.c_lflag;
2464 				for (i = 0; i < NCC; i++)
2465 					tty.c_cc[i] = termio.c_cc[i];
2466 			}
2467 		}
2468 	}
2469 
2470 	/* close the current file descriptor */
2471 	if (cur_disk != NULL) {
2472 		(void) close(cur_file);
2473 	}
2474 
2475 	/* execute the shell escape */
2476 	(void) system(s);
2477 
2478 	/* reopen file descriptor if one was open before */
2479 	if (cur_disk != NULL) {
2480 		if ((cur_file = open_disk(cur_disk->disk_path,
2481 			O_RDWR | O_NDELAY)) < 0) {
2482 			err_print("Error: can't reopen selected disk '%s'. \n",
2483 				cur_disk->disk_name);
2484 			fullabort();
2485 		}
2486 	}
2487 
2488 	/* Restore tty information */
2489 
2490 	if (isatty(0)) {
2491 		if (tty_flag > 0)
2492 			(void) ioctl(0, TCSETSW, &tty);
2493 		else if (tty_flag == 0) {
2494 			termio.c_iflag = tty.c_iflag;
2495 			termio.c_oflag = tty.c_oflag;
2496 			termio.c_cflag = tty.c_cflag;
2497 			termio.c_lflag = tty.c_lflag;
2498 			for (j = 0; j < NCC; j++)
2499 				termio.c_cc[j] = tty.c_cc[j];
2500 			(void) ioctl(0, TCSETAW, &termio);
2501 		}
2502 
2503 		if (isatty(1)) {
2504 			fmt_print("\n[Hit Return to continue] \n");
2505 			(void) fflush(stdin);
2506 			if (getchar() == EOF)
2507 				fullabort();
2508 		}
2509 	}
2510 	return (0);
2511 }
2512 
2513 void
2514 print_efi_string(char *vendor, char *product, char *revision,
2515     uint64_t capacity)
2516 {
2517 	char new_vendor[9];
2518 	char new_product[17];
2519 	char new_revision[5];
2520 	char capacity_string[10];
2521 	float scaled;
2522 	int i;
2523 
2524 	/* Strip whitespace from the end of inquiry strings */
2525 	(void) strlcpy(new_vendor, vendor, sizeof (new_vendor));
2526 	for (i = (strlen(new_vendor) - 1); i >= 0; i--) {
2527 		if (new_vendor[i] != 0x20) {
2528 			new_vendor[i+1] = '\0';
2529 			break;
2530 		}
2531 	}
2532 
2533 	(void) strlcpy(new_product, product, sizeof (new_product));
2534 	for (i = (strlen(new_product) - 1); i >= 0; i--) {
2535 		if (new_product[i] != 0x20) {
2536 			new_product[i+1] = '\0';
2537 			break;
2538 		}
2539 	}
2540 
2541 	(void) strlcpy(new_revision, revision, sizeof (new_revision));
2542 	for (i = (strlen(new_revision) - 1); i >= 0; i--) {
2543 		if (new_revision[i] != 0x20) {
2544 			new_revision[i+1] = '\0';
2545 			break;
2546 		}
2547 	}
2548 
2549 	/* Now build size string */
2550 	scaled = bn2mb(capacity);
2551 	if (scaled >= (float)1024.0 * 1024) {
2552 		(void) snprintf(capacity_string, sizeof (capacity_string),
2553 		    "%.2fTB", scaled/((float)1024.0 * 1024));
2554 	} else if (scaled >= (float)1024.0) {
2555 		(void) snprintf(capacity_string, sizeof (capacity_string),
2556 		    "%.2fGB", scaled/(float)1024.0);
2557 	} else {
2558 		(void) snprintf(capacity_string, sizeof (capacity_string),
2559 		    "%.2fMB", scaled);
2560 	}
2561 
2562 	fmt_print("<%s-%s-%s-%s>",
2563 	    new_vendor, new_product, new_revision, capacity_string);
2564 }
2565