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