comparison usr/src/cmd/format/io.c @ 0:c9caec207d52 b86

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