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