PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/format/io.c

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