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