Mercurial > illumos > onarm
annotate usr/src/cmd/format/io.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 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 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
26 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 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, §, &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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 } |