/usr/src/cmd/format/io.c
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
- /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
- /*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
- /*
- * This file contains I/O related functions.
- */
- #include "global.h"
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include <sys/tty.h>
- #include <sys/termio.h>
- #include <sys/termios.h>
- #include "startup.h"
- #include "misc.h"
- #include "menu_partition.h"
- #include "param.h"
- #include "menu.h"
- extern int data_lineno;
- extern char *space2str();
- extern long strtol();
- /*
- * This variable is used to determine whether a token is present in the pipe
- * already.
- */
- static char token_present = 0;
- /*
- * This variable always gives us access to the most recent token type
- */
- int last_token_type = 0;
- #ifdef __STDC__
- /*
- * Prototypes for ANSI C compilers
- */
- static int sup_get_token(char *);
- static void pushchar(int c);
- static int checkeof(void);
- static void flushline(void);
- static int strcnt(char *s1, char *s2);
- static int getbn(char *str, diskaddr_t *iptr);
- static void print_input_choices(int type, u_ioparam_t *param);
- static int slist_widest_str(slist_t *slist);
- static void ljust_print(char *str, int width);
- static int sup_inputchar(void);
- static void sup_pushchar(int c);
- static int geti64(char *str, uint64_t *iptr, uint64_t *wild);
- #else /* __STDC__ */
- /*
- * Prototypes for non-ANSI C compilers
- */
- static int sup_get_token();
- static void pushchar(int c);
- static int checkeof(void);
- static void flushline(void);
- static int strcnt(char *s1, char *s2);
- static int getbn(char *str, diskaddr_t *iptr);
- static void print_input_choices(int type, u_ioparam_t *param);
- static int slist_widest_str(slist_t *slist);
- static void ljust_print(char *str, int width);
- static int sup_inputchar(void);
- static void sup_pushchar(int c);
- static int geti64(char *str, uint64_t *iptr, uint64_t *wild);
- #endif /* __STDC__ */
- /*
- * This routine pushes the given character back onto the input stream.
- */
- static void
- pushchar(c)
- int c;
- {
- (void) ungetc(c, stdin);
- }
- /*
- * This routine checks the input stream for an eof condition.
- */
- static int
- checkeof()
- {
- return (feof(stdin));
- }
- /*
- * This routine gets the next token off the input stream. A token is
- * basically any consecutive non-white characters.
- */
- char *
- gettoken(inbuf)
- char *inbuf;
- {
- char *ptr = inbuf;
- int c, quoted = 0;
- retoke:
- /*
- * Remove any leading white-space.
- */
- while ((isspace(c = getchar())) && (c != '\n'))
- ;
- /*
- * If we are at the beginning of a line and hit the comment character,
- * flush the line and start again.
- */
- if (!token_present && c == COMMENT_CHAR) {
- token_present = 1;
- flushline();
- goto retoke;
- }
- /*
- * Loop on each character until we hit unquoted white-space.
- */
- while (!isspace(c) || quoted && (c != '\n')) {
- /*
- * If we hit eof, get out.
- */
- if (checkeof())
- return (NULL);
- /*
- * If we hit a double quote, change the state of quotedness.
- */
- if (c == '"')
- quoted = !quoted;
- /*
- * If there's room in the buffer, add the character to the end.
- */
- else if (ptr - inbuf < TOKEN_SIZE)
- *ptr++ = (char)c;
- /*
- * Get the next character.
- */
- c = getchar();
- }
- /*
- * Null terminate the token.
- */
- *ptr = '\0';
- /*
- * Peel off white-space still in the pipe.
- */
- while (isspace(c) && (c != '\n'))
- c = getchar();
- /*
- * If we hit another token, push it back and set state.
- */
- if (c != '\n') {
- pushchar(c);
- token_present = 1;
- } else
- token_present = 0;
- /*
- * Return the token.
- */
- return (inbuf);
- }
- /*
- * This routine removes the leading and trailing spaces from a token.
- */
- void
- clean_token(cleantoken, token)
- char *cleantoken, *token;
- {
- char *ptr;
- /*
- * Strip off leading white-space.
- */
- for (ptr = token; isspace(*ptr); ptr++)
- ;
- /*
- * Copy it into the clean buffer.
- */
- (void) strcpy(cleantoken, ptr);
- /*
- * Strip off trailing white-space.
- */
- for (ptr = cleantoken + strlen(cleantoken) - 1;
- isspace(*ptr) && (ptr >= cleantoken); ptr--) {
- *ptr = '\0';
- }
- }
- /*
- * This routine checks if a token is already present on the input line
- */
- int
- istokenpresent()
- {
- return (token_present);
- }
- /*
- * This routine flushes the rest of an input line if there is known
- * to be data in it. The flush has to be qualified because the newline
- * may have already been swallowed by the last gettoken.
- */
- static void
- flushline()
- {
- if (token_present) {
- /*
- * Flush the pipe to eol or eof.
- */
- while ((getchar() != '\n') && !checkeof())
- ;
- /*
- * Mark the pipe empty.
- */
- token_present = 0;
- }
- }
- /*
- * This routine returns the number of characters that are identical
- * between s1 and s2, stopping as soon as a mismatch is found.
- */
- static int
- strcnt(s1, s2)
- char *s1, *s2;
- {
- int i = 0;
- while ((*s1 != '\0') && (*s1++ == *s2++))
- i++;
- return (i);
- }
- /*
- * This routine converts the given token into an integer. The token
- * must convert cleanly into an integer with no unknown characters.
- * If the token is the wildcard string, and the wildcard parameter
- * is present, the wildcard value will be returned.
- */
- int
- geti(str, iptr, wild)
- char *str;
- int *iptr, *wild;
- {
- char *str2;
- /*
- * If there's a wildcard value and the string is wild, return the
- * wildcard value.
- */
- if (wild != NULL && strcmp(str, WILD_STRING) == 0)
- *iptr = *wild;
- else {
- /*
- * Conver the string to an integer.
- */
- *iptr = (int)strtol(str, &str2, 0);
- /*
- * If any characters didn't convert, it's an error.
- */
- if (*str2 != '\0') {
- err_print("`%s' is not an integer.\n", str);
- return (-1);
- }
- }
- return (0);
- }
- /*
- * This routine converts the given token into a long long. The token
- * must convert cleanly into a 64-bit integer with no unknown characters.
- * If the token is the wildcard string, and the wildcard parameter
- * is present, the wildcard value will be returned.
- */
- static int
- geti64(str, iptr, wild)
- char *str;
- uint64_t *iptr, *wild;
- {
- char *str2;
- /*
- * If there's a wildcard value and the string is wild, return the
- * wildcard value.
- */
- if ((wild != NULL) && (strcmp(str, WILD_STRING)) == 0) {
- *iptr = *wild;
- } else {
- /*
- * Conver the string to an integer.
- */
- *iptr = (uint64_t)strtoll(str, &str2, 0);
- /*
- * If any characters didn't convert, it's an error.
- */
- if (*str2 != '\0') {
- err_print("`%s' is not an integer.\n", str);
- return (-1);
- }
- }
- return (0);
- }
- /*
- * This routine converts the given string into a block number on the
- * current disk. The format of a block number is either a self-based
- * number, or a series of self-based numbers separated by slashes.
- * Any number preceeding the first slash is considered a cylinder value.
- * Any number succeeding the first slash but preceeding the second is
- * considered a head value. Any number succeeding the second slash is
- * considered a sector value. Any of these numbers can be wildcarded
- * to the highest possible legal value.
- */
- static int
- getbn(str, iptr)
- char *str;
- diskaddr_t *iptr;
- {
- char *cptr, *hptr, *sptr;
- int cyl, head, sect;
- int wild;
- diskaddr_t wild64;
- TOKEN buf;
- /*
- * Set cylinder pointer to beginning of string.
- */
- cptr = str;
- /*
- * Look for the first slash.
- */
- while ((*str != '\0') && (*str != '/'))
- str++;
- /*
- * If there wasn't one, convert string to an integer and return it.
- */
- if (*str == '\0') {
- wild64 = physsects() - 1;
- if (geti64(cptr, iptr, &wild64))
- return (-1);
- return (0);
- }
- /*
- * Null out the slash and set head pointer just beyond it.
- */
- *str++ = '\0';
- hptr = str;
- /*
- * Look for the second slash.
- */
- while ((*str != '\0') && (*str != '/'))
- str++;
- /*
- * If there wasn't one, sector pointer points to a .
- */
- if (*str == '\0')
- sptr = str;
- /*
- * If there was, null it out and set sector point just beyond it.
- */
- else {
- *str++ = '\0';
- sptr = str;
- }
- /*
- * Convert the cylinder part to an integer and store it.
- */
- clean_token(buf, cptr);
- wild = ncyl + acyl - 1;
- if (geti(buf, &cyl, &wild))
- return (-1);
- if ((cyl < 0) || (cyl >= (ncyl + acyl))) {
- err_print("`%d' is out of range.\n", cyl);
- return (-1);
- }
- /*
- * Convert the head part to an integer and store it.
- */
- clean_token(buf, hptr);
- wild = nhead - 1;
- if (geti(buf, &head, &wild))
- return (-1);
- if ((head < 0) || (head >= nhead)) {
- err_print("`%d' is out of range.\n", head);
- return (-1);
- }
- /*
- * Convert the sector part to an integer and store it.
- */
- clean_token(buf, sptr);
- wild = sectors(head) - 1;
- if (geti(buf, §, &wild))
- return (-1);
- if ((sect < 0) || (sect >= sectors(head))) {
- err_print("`%d' is out of range.\n", sect);
- return (-1);
- }
- /*
- * Combine the pieces into a block number and return it.
- */
- *iptr = chs2bn(cyl, head, sect);
- return (0);
- }
- /*
- * This routine is the basis for all input into the program. It
- * understands the semantics of a set of input types, and provides
- * consistent error messages for all input. It allows for default
- * values and prompt strings.
- */
- uint64_t
- input(type, promptstr, delim, param, deflt, cmdflag)
- int type;
- char *promptstr;
- int delim;
- u_ioparam_t *param;
- int *deflt;
- int cmdflag;
- {
- int interactive, help, i, length, index, tied;
- blkaddr_t bn;
- diskaddr_t bn64;
- char **str, **strings;
- TOKEN token, cleantoken;
- TOKEN token2, cleantoken2;
- char *arg;
- struct bounds *bounds;
- char *s;
- int value;
- int cyls, cylno;
- uint64_t blokno;
- float nmegs;
- float ngigs;
- char shell_argv[MAXPATHLEN];
- part_deflt_t *part_deflt;
- efi_deflt_t *efi_deflt;
- /*
- * Optional integer input has been added as a hack.
- * Function result is 1 if user typed anything.
- * Whatever they typed is returned in *deflt.
- * This permits us to distinguish between "no value",
- * and actually entering in some value, for instance.
- */
- if (type == FIO_OPINT) {
- assert(deflt != NULL);
- }
- reprompt:
- help = interactive = 0;
- /*
- * If we are inputting a command, flush any current input in the pipe.
- */
- if (cmdflag == CMD_INPUT)
- flushline();
- /*
- * Note whether the token is already present.
- */
- if (!token_present)
- interactive = 1;
- /*
- * Print the prompt.
- */
- fmt_print(promptstr);
- /*
- * If there is a default value, print it in a format appropriate
- * for the input type.
- */
- if (deflt != NULL) {
- switch (type) {
- case FIO_BN:
- #if !defined(lint) /* caller has aligned the pointer specifying FIO_BN */
- fmt_print("[%llu, ", *(diskaddr_t *)deflt);
- pr_dblock(fmt_print, *(diskaddr_t *)deflt);
- fmt_print("]");
- #endif
- break;
- case FIO_INT:
- fmt_print("[%d]", *deflt);
- break;
- case FIO_INT64:
- #if defined(lint)
- /* caller is longlong aligned specifying FIO_INT64 */
- efi_deflt = NULL;
- #else
- efi_deflt = (efi_deflt_t *)deflt;
- #endif
- fmt_print("[%llu]", efi_deflt->start_sector);
- break;
- case FIO_CSTR:
- case FIO_MSTR:
- strings = (char **)param->io_charlist;
- for (i = 0, str = strings; i < *deflt; i++, str++)
- ;
- fmt_print("[%s]", *str);
- break;
- case FIO_OSTR:
- fmt_print("[\"%s\"]", (char *)deflt);
- break;
- case FIO_SLIST:
- /*
- * Search for a string matching the default
- * value. If found, use it. Otherwise
- * assume the default value is actually
- * an illegal choice, and default to
- * the first item in the list.
- */
- s = find_string(param->io_slist, *deflt);
- if (s == (char *)NULL) {
- s = (param->io_slist)->str;
- }
- fmt_print("[%s]", s);
- break;
- case FIO_CYL:
- /*
- * Old-style partition size input, used to
- * modify complete partition tables
- */
- blokno = *(blkaddr32_t *)deflt;
- fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno,
- bn2c(blokno), bn2mb(blokno), bn2gb(blokno));
- break;
- case FIO_ECYL:
- /*
- * set up pointer to partition defaults
- * structure
- */
- part_deflt = (part_deflt_t *)deflt;
- /*
- * Build print format specifier. We use the
- * starting cylinder number which was entered
- * before this call to input(), in case the
- * user has changed it from the value in the
- * cur_parts->pinfo_map[].dkl_cylno
- * field for the current parition
- */
- /*
- * Determine the proper default end cylinder:
- * Start Cyl Default Size End Cylinder
- * 0 0 0
- * >0 0 Start Cyl
- * 0 >0 Default Size
- * (Cyls) - 1
- * >0 >0 (Start +
- * Default Size
- * (Cyls)) -1
- */
- if (part_deflt->deflt_size == 0) {
- cylno = part_deflt->start_cyl;
- } else if (part_deflt->start_cyl == 0) {
- cylno = bn2c(part_deflt->deflt_size) - 1;
- } else {
- cylno = (bn2c(part_deflt->deflt_size) +
- part_deflt->start_cyl) - 1;
- }
- fmt_print("[%ub, %uc, %de, %1.2fmb, %1.2fgb]",
- part_deflt->deflt_size,
- bn2c(part_deflt->deflt_size),
- cylno,
- bn2mb(part_deflt->deflt_size),
- bn2gb(part_deflt->deflt_size));
- break;
- case FIO_EFI:
- #if defined(lint)
- /* caller is longlong aligned when specifying FIO_EFI */
- efi_deflt = NULL;
- #else
- efi_deflt = (efi_deflt_t *)deflt;
- #endif
- fmt_print("[%llub, %llue, %llumb, %llugb, %llutb]",
- efi_deflt->end_sector,
- efi_deflt->start_sector + efi_deflt->end_sector - 1,
- (efi_deflt->end_sector * cur_blksz) /
- (1024 * 1024),
- (efi_deflt->end_sector * cur_blksz) /
- (1024 * 1024 * 1024),
- (efi_deflt->end_sector * cur_blksz) /
- ((uint64_t)1024 * 1024 * 1024 * 1024));
- break;
- case FIO_OPINT:
- /* no default value for optional input type */
- fmt_print("[default]");
- break;
- default:
- err_print("Error: unknown input type.\n");
- fullabort();
- }
- }
- /*
- * Print the delimiter character.
- */
- fmt_print("%c ", delim);
- /*
- * Get the token. If we hit eof, exit the program gracefully.
- */
- if (gettoken(token) == NULL)
- fullabort();
- /*
- * check if the user has issued (!) , escape to shell
- */
- if ((cmdflag == CMD_INPUT) && (token[0] == '!')) {
- /* get the list of arguments to shell command */
- (void) memset(shell_argv, 0, sizeof (shell_argv));
- /* initialize to the first token... */
- arg = &token[1];
- /*
- * ... and then collect all tokens until the end of
- * the line as arguments
- */
- do {
- /* skip empty tokens. */
- if (*arg == '\0')
- continue;
- /*
- * If either of the following two strlcat()
- * operations overflows, report an error and
- * exit gracefully.
- */
- if ((strlcat(shell_argv, arg, sizeof (shell_argv)) >=
- sizeof (shell_argv)) ||
- (strlcat(shell_argv, " ", sizeof (shell_argv)) >=
- sizeof (shell_argv))) {
- err_print("Error: Command line too long.\n");
- fullabort();
- }
- } while (token_present && (arg = gettoken(token)) != NULL);
- /* execute the shell command */
- (void) execute_shell(shell_argv, sizeof (shell_argv));
- redisplay_menu_list((char **)param->io_charlist);
- if (interactive) {
- goto reprompt;
- }
- }
- /*
- * Certain commands accept up to two tokens
- * Unfortunately, this is kind of a hack.
- */
- token2[0] = 0;
- cleantoken2[0] = 0;
- if (type == FIO_CYL || type == FIO_ECYL) {
- if (token_present) {
- if (gettoken(token2) == NULL)
- fullabort();
- clean_token(cleantoken2, token2);
- }
- }
- /*
- * Echo the token back to the user if it was in the pipe or we
- * are running out of a command file.
- */
- if (!interactive || option_f) {
- if (token2[0] == 0) {
- fmt_print("%s\n", token);
- } else {
- fmt_print("%s %s\n", token, token2);
- }
- }
- /*
- * If we are logging, echo the token to the log file. The else
- * is necessary here because the above printf will also put the
- * token in the log file.
- */
- else if (log_file) {
- log_print("%s %s\n", token, token2);
- }
- /*
- * If the token was not in the pipe and it wasn't a command, flush
- * the rest of the line to keep things in sync.
- */
- if (interactive && cmdflag != CMD_INPUT)
- flushline();
- /*
- * Scrub off the white-space.
- */
- clean_token(cleantoken, token);
- /*
- * If the input was a blank line and we weren't prompting
- * specifically for a blank line...
- */
- if ((strcmp(cleantoken, "") == 0) && (type != FIO_BLNK)) {
- /*
- * If there's a default, return it.
- */
- if (deflt != NULL) {
- if (type == FIO_OSTR) {
- /*
- * Duplicate and return the default string
- */
- return ((int)alloc_string((char *)deflt));
- } else if (type == FIO_SLIST) {
- /*
- * If we can find a match for the default
- * value in the list, return the default
- * value. If there's no match for the
- * default value, it's an illegal
- * choice. Return the first value in
- * the list.
- */
- s = find_string(param->io_slist, *deflt);
- if ((cur_label == L_TYPE_EFI) &&
- (s == (char *)NULL)) {
- return (*deflt);
- }
- if (s == (char *)NULL) {
- return ((param->io_slist)->value);
- } else {
- return (*deflt);
- }
- } else if (type == FIO_OPINT) {
- /*
- * The user didn't enter anything
- */
- return (0);
- } else if (type == FIO_ECYL) {
- return (part_deflt->deflt_size);
- } else if (type == FIO_INT64) {
- return (efi_deflt->start_sector);
- } else if (type == FIO_EFI) {
- return (efi_deflt->end_sector);
- } else {
- return (*deflt);
- }
- }
- /*
- * If the blank was not in the pipe, just reprompt.
- */
- if (interactive) {
- goto reprompt;
- }
- /*
- * If the blank was in the pipe, it's an error.
- */
- err_print("No default for this entry.\n");
- cmdabort(SIGINT);
- }
- /*
- * If token is a '?' or a 'h', it is a request for help.
- */
- if ((strcmp(cleantoken, "?") == 0) ||
- (strcmp(cleantoken, "h") == 0) ||
- (strcmp(cleantoken, "help") == 0)) {
- help = 1;
- }
- /*
- * Switch on the type of input expected.
- */
- switch (type) {
- /*
- * Expecting a disk block number.
- */
- case FIO_BN:
- /*
- * Parameter is the bounds of legal block numbers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting a block number from %llu (",
- bounds->lower);
- pr_dblock(fmt_print, bounds->lower);
- fmt_print(") to %llu (", bounds->upper);
- pr_dblock(fmt_print, bounds->upper);
- fmt_print(")\n");
- break;
- }
- /*
- * Convert token to a disk block number.
- */
- if (cur_label == L_TYPE_EFI) {
- if (geti64(cleantoken, (uint64_t *)&bn64,
- (uint64_t *)NULL))
- break;
- } else {
- if (getbn(cleantoken, &bn64))
- break;
- }
- /*
- * Check to be sure it is within the legal bounds.
- */
- if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
- err_print("`");
- pr_dblock(err_print, bn64);
- err_print("' is out of range.\n");
- break;
- }
- /*
- * It's ok, return it.
- */
- return (bn64);
- /*
- * Expecting an integer.
- */
- case FIO_INT:
- /*
- * Parameter is the bounds of legal integers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting an integer from %llu",
- bounds->lower);
- fmt_print(" to %llu\n", bounds->upper);
- break;
- }
- /*
- * Convert the token into an integer.
- */
- if (geti(cleantoken, (int *)&bn, (int *)NULL))
- break;
- /*
- * Check to be sure it is within the legal bounds.
- */
- if ((bn < bounds->lower) || (bn > bounds->upper)) {
- err_print("`%lu' is out of range.\n", bn);
- break;
- }
- /*
- * If it's ok, return it.
- */
- return (bn);
- case FIO_INT64:
- /*
- * Parameter is the bounds of legal integers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting an integer from %llu",
- bounds->lower);
- fmt_print(" to %llu\n", bounds->upper);
- break;
- }
- /*
- * Convert the token into an integer.
- */
- if (geti64(cleantoken, (uint64_t *)&bn64, (uint64_t *)NULL)) {
- break;
- }
- /*
- * Check to be sure it is within the legal bounds.
- */
- if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
- err_print("`%llu' is out of range.\n", bn64);
- break;
- }
- /*
- * If it's ok, return it.
- */
- return (bn64);
- /*
- * Expecting an integer, or no input.
- */
- case FIO_OPINT:
- /*
- * Parameter is the bounds of legal integers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting an integer from %llu",
- bounds->lower);
- fmt_print(" to %llu, or no input\n", bounds->upper);
- break;
- }
- /*
- * Convert the token into an integer.
- */
- if (geti(cleantoken, (int *)&bn, (int *)NULL))
- break;
- /*
- * Check to be sure it is within the legal bounds.
- */
- if ((bn < bounds->lower) || (bn > bounds->upper)) {
- err_print("`%lu' is out of range.\n", bn);
- break;
- }
- /*
- * For optional case, return 1 indicating that
- * the user actually did enter something.
- */
- if (!deflt)
- *deflt = bn;
- return (1);
- /*
- * Expecting a closed string. This means that the input
- * string must exactly match one of the strings passed in
- * as the parameter.
- */
- case FIO_CSTR:
- /*
- * The parameter is a null terminated array of character
- * pointers, each one pointing to a legal input string.
- */
- strings = (char **)param->io_charlist;
- /*
- * Walk through the legal strings, seeing if any of them
- * match the token. If a match is made, return the index
- * of the string that was matched.
- */
- for (str = strings; *str != NULL; str++)
- if (strcmp(cleantoken, *str) == 0)
- return (str - strings);
- /*
- * Print help message if required.
- */
- if (help) {
- print_input_choices(type, param);
- } else {
- err_print("`%s' is not expected.\n", cleantoken);
- }
- break;
- /*
- * Expecting a matched string. This means that the input
- * string must either match one of the strings passed in,
- * or be a unique abbreviation of one of them.
- */
- case FIO_MSTR:
- /*
- * The parameter is a null terminated array of character
- * pointers, each one pointing to a legal input string.
- */
- strings = (char **)param->io_charlist;
- length = index = tied = 0;
- /*
- * Loop through the legal input strings.
- */
- for (str = strings; *str != NULL; str++) {
- /*
- * See how many characters of the token match
- * this legal string.
- */
- i = strcnt(cleantoken, *str);
- /*
- * If it's not the whole token, then it's not a match.
- */
- if ((uint_t)i < strlen(cleantoken))
- continue;
- /*
- * If it ties with another input, remember that.
- */
- if (i == length)
- tied = 1;
- /*
- * If it matches the most so far, record that.
- */
- if (i > length) {
- index = str - strings;
- tied = 0;
- length = i;
- }
- }
- /*
- * Print help message if required.
- */
- if (length == 0) {
- if (help) {
- print_input_choices(type, param);
- } else {
- err_print("`%s' is not expected.\n",
- cleantoken);
- }
- break;
- }
- /*
- * If the abbreviation was non-unique, it's an error.
- */
- if (tied) {
- err_print("`%s' is ambiguous.\n", cleantoken);
- break;
- }
- /*
- * We matched one. Return the index of the string we matched.
- */
- return (index);
- /*
- * Expecting an open string. This means that any string is legal.
- */
- case FIO_OSTR:
- /*
- * Print a help message if required.
- */
- if (help) {
- fmt_print("Expecting a string\n");
- break;
- }
- /*
- * alloc a copy of the string and return it
- */
- return ((int)alloc_string(token));
- /*
- * Expecting a blank line.
- */
- case FIO_BLNK:
- /*
- * We are always in non-echo mode when we are inputting
- * this type. We echo the newline as a carriage return
- * only so the prompt string will be covered over.
- */
- nolog_print("\015");
- /*
- * If we are logging, send a newline to the log file.
- */
- if (log_file)
- log_print("\n");
- /*
- * There is no value returned for this type.
- */
- return (0);
- /*
- * Expecting one of the entries in a string list.
- * Accept unique abbreviations.
- * Return the value associated with the matched string.
- */
- case FIO_SLIST:
- i = find_value((slist_t *)param->io_slist,
- cleantoken, &value);
- if (i == 1) {
- return (value);
- } else {
- /*
- * Print help message if required.
- */
- if (help) {
- print_input_choices(type, param);
- } else {
- if (i == 0)
- err_print("`%s' not expected.\n",
- cleantoken);
- else
- err_print("`%s' is ambiguous.\n",
- cleantoken);
- }
- }
- break;
- /*
- * Cylinder size input when modifying a complete partition map
- */
- case FIO_CYL:
- /*
- * Parameter is the bounds of legal block numbers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- assert(bounds->lower == 0);
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting up to %llu blocks,",
- bounds->upper);
- fmt_print(" %u cylinders, ", bn2c(bounds->upper));
- fmt_print(" %1.2f megabytes, ", bn2mb(bounds->upper));
- fmt_print("or %1.2f gigabytes\n", bn2gb(bounds->upper));
- break;
- }
- /*
- * Parse the first token: try to find 'b', 'c' or 'm'
- */
- s = cleantoken;
- while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
- s++;
- }
- /*
- * If we found a conversion specifier, second token is unused
- * Otherwise, the second token should supply it.
- */
- if (*s != 0) {
- value = *s;
- *s = 0;
- } else {
- value = cleantoken2[0];
- }
- /*
- * If the token is the wild card, simply supply the max
- * This order allows the user to specify the maximum in
- * either blocks/cyls/megabytes - a convenient fiction.
- */
- if (strcmp(cleantoken, WILD_STRING) == 0) {
- return (bounds->upper);
- }
- /*
- * Allow the user to specify zero with no units,
- * by just defaulting to cylinders.
- */
- if (strcmp(cleantoken, "0") == 0) {
- value = 'c';
- }
- /*
- * If there's a decimal point, but no unit specification,
- * let's assume megabytes.
- */
- if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
- value = 'm';
- }
- /*
- * Handle each unit type we support
- */
- switch (value) {
- case 'b':
- /*
- * Convert token to a disk block number.
- */
- if (geti64(cleantoken, &bn64, &bounds->upper))
- break;
- /*
- * Check to be sure it is within the legal bounds.
- */
- if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
- err_print(
- "`%llub' is out of the range %llu "
- "to %llu\n",
- bn64, bounds->lower, bounds->upper);
- break;
- }
- /*
- * Verify the block lies on a cylinder boundary
- */
- if ((bn64 % spc()) != 0) {
- err_print(
- "partition size must be a multiple of "
- "%u blocks to lie on a cylinder boundary\n",
- spc());
- err_print(
- "%llu blocks is approximately %u cylinders,"
- " %1.2f megabytes or %1.2f gigabytes\n",
- bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
- break;
- }
- return (bn64);
- case 'c':
- /*
- * Convert token from a number of cylinders to
- * a number of blocks.
- */
- i = bn2c(bounds->upper);
- if (geti(cleantoken, &cyls, &i))
- break;
- /*
- * Check the bounds - cyls is number of cylinders
- */
- if (cyls > (bounds->upper/spc())) {
- err_print("`%dc' is out of range\n", cyls);
- break;
- }
- /*
- * Convert cylinders to blocks and return
- */
- return (cyls * spc());
- case 'm':
- /*
- * Convert token from megabytes to a block number.
- */
- if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- /*
- * Check the bounds
- */
- if (nmegs > bn2mb(bounds->upper)) {
- err_print("`%1.2fmb' is out of range\n", nmegs);
- break;
- }
- /*
- * Convert to blocks
- */
- bn64 = mb2bn(nmegs);
- /*
- * Round value up to nearest cylinder
- */
- i = spc();
- bn64 = ((bn64 + (i-1)) / i) * i;
- return (bn64);
- case 'g':
- /*
- * Convert token from gigabytes to a block number.
- */
- if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- /*
- * Check the bounds
- */
- if (ngigs > bn2gb(bounds->upper)) {
- err_print("`%1.2fgb' is out of range\n", ngigs);
- break;
- }
- /*
- * Convert to blocks
- */
- bn64 = gb2bn(ngigs);
- /*
- * Round value up to nearest cylinder
- */
- i = spc();
- bn64 = ((bn64 + (i-1)) / i) * i;
- return (bn64);
- default:
- err_print(
- "Please specify units in either b(blocks), c(cylinders), m(megabytes) \
- or g(gigabytes)\n");
- break;
- }
- break;
- case FIO_ECYL:
- /*
- * Parameter is the bounds of legal block numbers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- assert(bounds->lower == 0);
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting up to %llu blocks,",
- bounds->upper);
- fmt_print(" %u cylinders, ",
- bn2c(bounds->upper));
- fmt_print(" %u end cylinder, ",
- (uint_t)(bounds->upper / spc()));
- fmt_print(" %1.2f megabytes, ",
- bn2mb(bounds->upper));
- fmt_print("or %1.2f gigabytes\n",
- bn2gb(bounds->upper));
- break;
- }
- /*
- * Parse the first token: try to find 'b', 'c', 'e'
- * or 'm'
- */
- s = cleantoken;
- while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
- s++;
- }
- /*
- * If we found a conversion specifier, second token is
- * unused Otherwise, the second token should supply it.
- */
- if (*s != 0) {
- value = *s;
- *s = 0;
- } else {
- value = cleantoken2[0];
- }
- /*
- * If the token is the wild card, simply supply the max
- * This order allows the user to specify the maximum in
- * either blocks/cyls/megabytes - a convenient fiction.
- */
- if (strcmp(cleantoken, WILD_STRING) == 0) {
- return (bounds->upper);
- }
- /*
- * Allow the user to specify zero with no units,
- * by just defaulting to cylinders.
- */
- if (value != 'e' && strcmp(cleantoken, "0") == 0) {
- value = 'c';
- }
- /*
- * If there's a decimal point, but no unit
- * specification, let's assume megabytes.
- */
- if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
- value = 'm';
- }
- /*
- * Handle each unit type we support
- */
- switch (value) {
- case 'b':
- /*
- * Convert token to a disk block number.
- */
- if (geti64(cleantoken, &bn64, &bounds->upper))
- break;
- /*
- * Check to be sure it is within the
- * legal bounds.
- */
- if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
- err_print(
- "`%llub' is out of the range %llu to %llu\n",
- bn64, bounds->lower, bounds->upper);
- break;
- }
- /*
- * Verify the block lies on a cylinder
- * boundary
- */
- if ((bn64 % spc()) != 0) {
- err_print(
- "partition size must be a multiple of %u "
- "blocks to lie on a cylinder boundary\n",
- spc());
- err_print(
- "%llu blocks is approximately %u cylinders,"
- " %1.2f megabytes or %1.2f gigabytes\n",
- bn64, bn2c(bn64), bn2mb(bn64), bn2gb(bn64));
- break;
- }
- return (bn64);
- case 'e':
- /*
- * Token is ending cylinder
- */
- /* convert token to integer */
- if (geti(cleantoken, &cylno, (int *)NULL)) {
- break;
- }
- /*
- * check that input cylno isn't before the current
- * starting cylinder number. Note that we are NOT
- * using the starting cylinder from
- * cur_parts->pinfo_map[].dkl_cylno!
- */
- if (cylno < part_deflt->start_cyl) {
- err_print(
- "End cylinder must fall on or after start cylinder %u\n",
- part_deflt->start_cyl);
- break;
- }
- /*
- * calculate cylinder number of upper boundary, and
- * verify that our input is within range
- */
- i = (bn2c(bounds->upper) + part_deflt->start_cyl - 1);
- if (cylno > i) {
- err_print(
- "End cylinder %d is beyond max cylinder %d\n",
- cylno, i);
- break;
- }
- /*
- * calculate number of cylinders based on input
- */
- cyls = ((cylno - part_deflt->start_cyl) + 1);
- return (cyls * spc());
- case 'c':
- /*
- * Convert token from a number of
- * cylinders to a number of blocks.
- */
- i = bn2c(bounds->upper);
- if (geti(cleantoken, &cyls, &i))
- break;
- /*
- * Check the bounds - cyls is number of
- * cylinders
- */
- if (cyls > (bounds->upper/spc())) {
- err_print("`%dc' is out of range\n", cyls);
- break;
- }
- /*
- * Convert cylinders to blocks and
- * return
- */
- return (cyls * spc());
- case 'm':
- /*
- * Convert token from megabytes to a
- * block number.
- */
- if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- /*
- * Check the bounds
- */
- if (nmegs > bn2mb(bounds->upper)) {
- err_print("`%1.2fmb' is out of range\n", nmegs);
- break;
- }
- /*
- * Convert to blocks
- */
- bn64 = mb2bn(nmegs);
- /*
- * Round value up to nearest cylinder
- */
- i = spc();
- bn64 = ((bn64 + (i-1)) / i) * i;
- return (bn64);
- case 'g':
- /*
- * Convert token from gigabytes to a
- * block number.
- */
- if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- /*
- * Check the bounds
- */
- if (ngigs > bn2gb(bounds->upper)) {
- err_print("`%1.2fgb' is out of range\n", ngigs);
- break;
- }
- /*
- * Convert to blocks
- */
- bn64 = gb2bn(ngigs);
- /*
- * Round value up to nearest cylinder
- */
- i = spc();
- bn64 = ((bn64 + (i-1)) / i) * i;
- return (bn64);
- default:
- err_print(
- "Please specify units in either b(blocks), c(cylinders), e(end cylinder),\n");
- err_print("m(megabytes) or g(gigabytes)\n");
- break;
- }
- break;
- case FIO_EFI:
- /*
- * Parameter is the bounds of legal block numbers.
- */
- bounds = (struct bounds *)¶m->io_bounds;
- /*
- * Print help message if required.
- */
- if (help) {
- fmt_print("Expecting up to %llu sectors,",
- cur_parts->etoc->efi_last_u_lba);
- fmt_print("or %llu megabytes,",
- (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
- (1024 * 1024));
- fmt_print("or %llu gigabytes\n",
- (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
- (1024 * 1024 * 1024));
- fmt_print("or %llu terabytes\n",
- (cur_parts->etoc->efi_last_u_lba * cur_blksz)/
- ((uint64_t)1024 * 1024 * 1024 * 1024));
- break;
- }
- /*
- * Parse the first token: try to find 'b', 'c', 'e'
- * or 'm'
- */
- s = cleantoken;
- while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
- s++;
- }
- /*
- * If we found a conversion specifier, second token is
- * unused Otherwise, the second token should supply it.
- */
- if (*s != 0) {
- value = *s;
- *s = 0;
- } else {
- value = cleantoken2[0];
- }
- /*
- * If the token is the wild card, simply supply the max
- * This order allows the user to specify the maximum in
- * either blocks/cyls/megabytes - a convenient fiction.
- */
- if (strcmp(cleantoken, WILD_STRING) == 0) {
- return (bounds->upper - EFI_MIN_RESV_SIZE -
- efi_deflt->start_sector);
- }
- /*
- * Allow the user to specify zero with no units,
- * by just defaulting to sectors.
- */
- if (value != 'e' && strcmp(cleantoken, "0") == 0) {
- value = 'm';
- }
- /*
- * If there's a decimal point, but no unit
- * specification, let's assume megabytes.
- */
- if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
- value = 'm';
- }
- /*
- * Handle each unit type we support
- */
- switch (value) {
- case 'b':
- /*
- * Token is number of blocks
- */
- if (geti64(cleantoken, &blokno, (uint64_t *)NULL)) {
- break;
- }
- if (blokno > bounds->upper) {
- err_print(
- "Number of blocks must be less that the total available blocks.\n");
- break;
- }
- return (blokno);
- case 'e':
- /*
- * Token is ending block number
- */
- /* convert token to integer */
- if (geti64(cleantoken, &blokno, (uint64_t *)NULL)) {
- break;
- }
- /*
- * Some sanity check
- */
- if (blokno < efi_deflt->start_sector) {
- err_print(
- "End Sector must fall on or after start sector %llu\n",
- efi_deflt->start_sector);
- break;
- }
- /*
- * verify that our input is within range
- */
- if (blokno > cur_parts->etoc->efi_last_u_lba) {
- err_print(
- "End Sector %llu is beyond max Sector %llu\n",
- blokno, cur_parts->etoc->efi_last_u_lba);
- break;
- }
- /*
- * calculate number of blocks based on input
- */
- return (blokno - efi_deflt->start_sector + 1);
- case 'm':
- /*
- * Convert token from megabytes to a
- * block number.
- */
- if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- /*
- * Check the bounds
- */
- if (nmegs > bn2mb(bounds->upper - bounds->lower)) {
- err_print("`%1.2fmb' is out of range\n", nmegs);
- break;
- }
- return (mb2bn(nmegs));
- case 'g':
- if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- if (nmegs > bn2gb(bounds->upper - bounds->lower)) {
- err_print("`%1.2fgb' is out of range\n", nmegs);
- break;
- }
- return (gb2bn(nmegs));
- case 't':
- if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
- err_print("`%s' is not recognized\n",
- cleantoken);
- break;
- }
- if (nmegs > bn2tb(bounds->upper - bounds->lower)) {
- err_print("`%1.2ftb' is out of range\n", nmegs);
- break;
- }
- return (uint64_t)((float)nmegs * 1024.0 *
- 1024.0 * 1024.0 * 1024.0 / cur_blksz);
- default:
- err_print(
- "Please specify units in either b(number of blocks), e(end sector),\n");
- err_print(" g(gigabytes), m(megabytes)");
- err_print(" or t(terabytes)\n");
- break;
- }
- break;
- /*
- * If we don't recognize the input type, it's bad news.
- */
- default:
- err_print("Error: unknown input type.\n");
- fullabort();
- }
- /*
- * If we get here, it's because some error kept us from accepting
- * the token. If we are running out of a command file, gracefully
- * leave the program. If we are interacting with the user, simply
- * reprompt. If the token was in the pipe, abort the current command.
- */
- if (option_f)
- fullabort();
- else if (interactive)
- goto reprompt;
- else
- cmdabort(SIGINT);
- /*
- * Never actually reached.
- */
- return (-1);
- }
- /*
- * Print input choices
- */
- static void
- print_input_choices(type, param)
- int type;
- u_ioparam_t *param;
- {
- char **sp;
- slist_t *lp;
- int width;
- int col;
- int ncols;
- switch (type) {
- case FIO_CSTR:
- fmt_print("Expecting one of the following:\n");
- goto common;
- case FIO_MSTR:
- fmt_print("Expecting one of the following: ");
- fmt_print("(abbreviations ok):\n");
- common:
- for (sp = (char **)param->io_charlist; *sp != NULL; sp++) {
- fmt_print("\t%s\n", *sp);
- }
- break;
- case FIO_SLIST:
- fmt_print("Expecting one of the following: ");
- fmt_print("(abbreviations ok):\n");
- /*
- * Figure out the width of the widest string
- */
- width = slist_widest_str((slist_t *)param->io_slist);
- width += 4;
- /*
- * If the help messages are empty, print the
- * possible choices in left-justified columns
- */
- lp = (slist_t *)param->io_slist;
- if (*lp->help == 0) {
- col = 0;
- ncols = 60 / width;
- for (; lp->str != NULL; lp++) {
- if (col == 0)
- fmt_print("\t");
- ljust_print(lp->str,
- (++col == ncols) ? 0 : width);
- if (col == ncols) {
- col = 0;
- fmt_print("\n");
- }
- }
- if (col != 0)
- fmt_print("\n");
- } else {
- /*
- * With help messages, print each choice,
- * and help message, on its own line.
- */
- for (; lp->str != NULL; lp++) {
- fmt_print("\t");
- ljust_print(lp->str, width);
- fmt_print("- %s\n", lp->help);
- }
- }
- break;
- default:
- err_print("Error: unknown input type.\n");
- fullabort();
- }
- fmt_print("\n");
- }
- /*
- * Search a string list for a particular string.
- * Use minimum recognition, to accept unique abbreviations
- * Return the number of possible matches found.
- * If only one match was found, return the arbitrary value
- * associated with the matched string in match_value.
- */
- int
- find_value(slist, match_str, match_value)
- slist_t *slist;
- char *match_str;
- int *match_value;
- {
- int i;
- int nmatches;
- int length;
- int match_length;
- nmatches = 0;
- length = 0;
- match_length = strlen(match_str);
- for (; slist->str != NULL; slist++) {
- /*
- * See how many characters of the token match
- */
- i = strcnt(match_str, slist->str);
- /*
- * If it's not the whole token, then it's not a match.
- */
- if (i < match_length)
- continue;
- /*
- * If it ties with another input, remember that.
- */
- if (i == length)
- nmatches++;
- /*
- * If it matches the most so far, record that.
- */
- if (i > length) {
- *match_value = slist->value;
- nmatches = 1;
- length = i;
- }
- }
- return (nmatches);
- }
- /*
- * Search a string list for a particular value.
- * Return the string associated with that value.
- */
- char *
- find_string(slist, match_value)
- slist_t *slist;
- int match_value;
- {
- for (; slist->str != NULL; slist++) {
- if (slist->value == match_value) {
- return (slist->str);
- }
- }
- return ((char *)NULL);
- }
- /*
- * Return the width of the widest string in an slist
- */
- static int
- slist_widest_str(slist)
- slist_t *slist;
- {
- int i;
- int width;
- width = 0;
- for (; slist->str != NULL; slist++) {
- if ((i = strlen(slist->str)) > width)
- width = i;
- }
- return (width);
- }
- /*
- * Print a string left-justified to a fixed width.
- */
- static void
- ljust_print(str, width)
- char *str;
- int width;
- {
- int i;
- fmt_print("%s", str);
- for (i = width - strlen(str); i > 0; i--) {
- fmt_print(" ");
- }
- }
- /*
- * This routine is a modified version of printf. It handles the cases
- * of silent mode and logging; other than that it is identical to the
- * library version.
- */
- /*PRINTFLIKE1*/
- void
- fmt_print(char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- /*
- * If we are running silent, skip it.
- */
- if (option_s == 0) {
- /*
- * Do the print to standard out.
- */
- if (need_newline) {
- (void) printf("\n");
- }
- (void) vprintf(format, ap);
- /*
- * If we are logging, also print to the log file.
- */
- if (log_file) {
- if (need_newline) {
- (void) fprintf(log_file, "\n");
- }
- (void) vfprintf(log_file, format, ap);
- (void) fflush(log_file);
- }
- }
- need_newline = 0;
- va_end(ap);
- }
- /*
- * This routine is a modified version of printf. It handles the cases
- * of silent mode; other than that it is identical to the
- * library version. It differs from the above printf in that it does
- * not print the message to a log file.
- */
- /*PRINTFLIKE1*/
- void
- nolog_print(char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- /*
- * If we are running silent, skip it.
- */
- if (option_s == 0) {
- /*
- * Do the print to standard out.
- */
- if (need_newline) {
- (void) printf("\n");
- }
- (void) vprintf(format, ap);
- }
- va_end(ap);
- need_newline = 0;
- }
- /*
- * This routine is a modified version of printf. It handles the cases
- * of silent mode, and only prints the message to the log file, not
- * stdout. Other than that is identical to the library version.
- */
- /*PRINTFLIKE1*/
- void
- log_print(char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- /*
- * If we are running silent, skip it.
- */
- if (option_s == 0) {
- /*
- * Do the print to the log file.
- */
- if (need_newline) {
- (void) fprintf(log_file, "\n");
- }
- (void) vfprintf(log_file, format, ap);
- (void) fflush(log_file);
- }
- va_end(ap);
- need_newline = 0;
- }
- /*
- * This routine is a modified version of printf. It prints the message
- * to stderr, and to the log file is appropriate.
- * Other than that is identical to the library version.
- */
- /*PRINTFLIKE1*/
- void
- err_print(char *format, ...)
- {
- va_list ap;
- va_start(ap, format);
- /*
- * Flush anything pending to stdout
- */
- if (need_newline) {
- (void) printf("\n");
- }
- (void) fflush(stdout);
- /*
- * Do the print to stderr.
- */
- (void) vfprintf(stderr, format, ap);
- /*
- * If we are logging, also print to the log file.
- */
- if (log_file) {
- if (need_newline) {
- (void) fprintf(log_file, "\n");
- }
- (void) vfprintf(log_file, format, ap);
- (void) fflush(log_file);
- }
- va_end(ap);
- need_newline = 0;
- }
- /*
- * Print a number of characters from a buffer. The buffer
- * does not need to be null-terminated. Since the data
- * may be coming from a device, we cannot be sure the
- * data is not crud, so be rather defensive.
- */
- void
- print_buf(buf, nbytes)
- char *buf;
- int nbytes;
- {
- int c;
- while (nbytes-- > 0) {
- c = *buf++;
- if (isascii(c) && isprint(c)) {
- fmt_print("%c", c);
- } else
- break;
- }
- }
- #ifdef not
- /*
- * This routine prints out a message describing the given ctlr.
- * The message is identical to the one printed by the kernel during
- * booting.
- */
- void
- pr_ctlrline(ctlr)
- register struct ctlr_info *ctlr;
- {
- fmt_print(" %s%d at %s 0x%x ",
- ctlr->ctlr_cname, ctlr->ctlr_num,
- space2str(ctlr->ctlr_space), ctlr->ctlr_addr);
- if (ctlr->ctlr_vec != 0)
- fmt_print("vec 0x%x ", ctlr->ctlr_vec);
- else
- fmt_print("pri %d ", ctlr->ctlr_prio);
- fmt_print("\n");
- }
- #endif /* not */
- /*
- * This routine prints out a message describing the given disk.
- * The message is identical to the one printed by the kernel during
- * booting.
- */
- void
- pr_diskline(disk, num)
- register struct disk_info *disk;
- int num;
- {
- struct ctlr_info *ctlr = disk->disk_ctlr;
- struct disk_type *type = disk->disk_type;
- fmt_print(" %4d. %s ", num, disk->disk_name);
- if ((type != NULL) && (disk->label_type == L_TYPE_SOLARIS)) {
- fmt_print("<%s cyl %u alt %u hd %u sec %u>",
- type->dtype_asciilabel, type->dtype_ncyl,
- type->dtype_acyl, type->dtype_nhead,
- type->dtype_nsect);
- } else if ((type != NULL) && (disk->label_type == L_TYPE_EFI)) {
- cur_blksz = disk->disk_lbasize;
- print_efi_string(type->vendor, type->product,
- type->revision, type->capacity);
- } else if (disk->disk_flags & DSK_RESERVED) {
- fmt_print("<drive not available: reserved>");
- } else if (disk->disk_flags & DSK_UNAVAILABLE) {
- fmt_print("<drive not available>");
- } else {
- fmt_print("<drive type unknown>");
- }
- if (chk_volname(disk)) {
- fmt_print(" ");
- print_volname(disk);
- }
- fmt_print("\n");
- if (disk->devfs_name != NULL) {
- fmt_print(" %s\n", disk->devfs_name);
- } else {
- fmt_print(" %s%d at %s%d slave %d\n",
- ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
- ctlr->ctlr_cname, ctlr->ctlr_num,
- disk->disk_dkinfo.dki_slave);
- }
- #ifdef OLD
- fmt_print(" %4d. %s at %s%d slave %d", num, disk->disk_name,
- ctlr->ctlr_cname, ctlr->ctlr_num, disk->disk_dkinfo.dki_slave);
- if (chk_volname(disk)) {
- fmt_print(": ");
- print_volname(disk);
- }
- fmt_print("\n");
- if (type != NULL) {
- fmt_print(
- " %s%d: <%s cyl %u alt %u hd %u sec %u>\n",
- ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit,
- type->dtype_asciilabel, type->dtype_ncyl,
- type->dtype_acyl, type->dtype_nhead,
- type->dtype_nsect);
- } else {
- fmt_print(" %s%d: <drive type unknown>\n",
- ctlr->ctlr_dname, disk->disk_dkinfo.dki_unit);
- }
- #endif /* OLD */
- }
- /*
- * This routine prints out a given disk block number in cylinder/head/sector
- * format. It uses the printing routine passed in to do the actual output.
- */
- void
- pr_dblock(void (*func)(char *, ...), diskaddr_t bn)
- {
- if (cur_label == L_TYPE_SOLARIS) {
- (*func)("%u/%u/%u", bn2c(bn),
- bn2h(bn), bn2s(bn));
- } else {
- (*func)("%llu", bn);
- }
- }
- /*
- * This routine inputs a character from the data file. It understands
- * the use of '\' to prevent interpretation of a newline. It also keeps
- * track of the current line in the data file via a global variable.
- */
- static int
- sup_inputchar()
- {
- int c;
- /*
- * Input the character.
- */
- c = getc(data_file);
- /*
- * If it's not a backslash, return it.
- */
- if (c != '\\')
- return (c);
- /*
- * It was a backslash. Get the next character.
- */
- c = getc(data_file);
- /*
- * If it was a newline, update the line counter and get the next
- * character.
- */
- if (c == '\n') {
- data_lineno++;
- c = getc(data_file);
- }
- /*
- * Return the character.
- */
- return (c);
- }
- /*
- * This routine pushes a character back onto the input pipe for the data file.
- */
- static void
- sup_pushchar(c)
- int c;
- {
- (void) ungetc(c, data_file);
- }
- /*
- * Variables to support pushing back tokens
- */
- static int have_pushed_token = 0;
- static TOKEN pushed_buf;
- static int pushed_token;
- /*
- * This routine inputs a token from the data file. A token is a series
- * of contiguous non-white characters or a recognized special delimiter
- * character. Use of the wrapper lets us always have the value of the
- * last token around, which is useful for error recovery.
- */
- int
- sup_gettoken(buf)
- char *buf;
- {
- last_token_type = sup_get_token(buf);
- return (last_token_type);
- }
- static int
- sup_get_token(buf)
- char *buf;
- {
- char *ptr = buf;
- int c, quoted = 0;
- /*
- * First check for presence of push-backed token.
- * If so, return it.
- */
- if (have_pushed_token) {
- have_pushed_token = 0;
- bcopy(pushed_buf, buf, TOKEN_SIZE+1);
- return (pushed_token);
- }
- /*
- * Zero out the returned token buffer
- */
- bzero(buf, TOKEN_SIZE + 1);
- /*
- * Strip off leading white-space.
- */
- while ((isspace(c = sup_inputchar())) && (c != '\n'))
- ;
- /*
- * Read in characters until we hit unquoted white-space.
- */
- for (; !isspace(c) || quoted; c = s