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, §, &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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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