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