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