#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 <sys/efi_partition.h>
#include "startup.h"
#include "misc.h"
#include "menu_partition.h"
#include "param.h"
#include "menu.h"
extern int data_lineno;
extern char *space2str(uint_t);
static char token_present = 0;
int last_token_type = 0;
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);
static void
pushchar(int c)
{
(void) ungetc(c, stdin);
}
static int
checkeof(void)
{
return (feof(stdin));
}
char *
gettoken(char *inbuf)
{
char *ptr = inbuf;
int c, quoted = 0;
retoke:
while ((isspace(c = getchar())) && (c != '\n'))
;
if (!token_present && c == COMMENT_CHAR) {
token_present = 1;
flushline();
goto retoke;
}
while (!isspace(c) || quoted && (c != '\n')) {
if (checkeof())
return (NULL);
if (c == '"')
quoted = !quoted;
else if (ptr - inbuf < TOKEN_SIZE)
*ptr++ = (char)c;
c = getchar();
}
*ptr = '\0';
while (isspace(c) && (c != '\n'))
c = getchar();
if (c != '\n') {
pushchar(c);
token_present = 1;
} else
token_present = 0;
return (inbuf);
}
void
clean_token(char *cleantoken, char *token)
{
char *ptr;
for (ptr = token; isspace(*ptr); ptr++)
;
(void) strcpy(cleantoken, ptr);
for (ptr = cleantoken + strlen(cleantoken) - 1;
isspace(*ptr) && (ptr >= cleantoken); ptr--) {
*ptr = '\0';
}
}
int
istokenpresent(void)
{
return (token_present);
}
static void
flushline(void)
{
if (token_present) {
while ((getchar() != '\n') && !checkeof())
;
token_present = 0;
}
}
static int
strcnt(char *s1, char *s2)
{
int i = 0;
while ((*s1 != '\0') && (*s1++ == *s2++))
i++;
return (i);
}
int
geti(char *str, int *iptr, int *wild)
{
char *str2;
if (wild != NULL && strcmp(str, WILD_STRING) == 0)
*iptr = *wild;
else {
*iptr = (int)strtol(str, &str2, 0);
if (*str2 != '\0') {
err_print("`%s' is not an integer.\n", str);
return (-1);
}
}
return (0);
}
static int
geti64(char *str, uint64_t *iptr, uint64_t *wild)
{
char *str2;
if ((wild != NULL) && (strcmp(str, WILD_STRING)) == 0) {
*iptr = *wild;
} else {
*iptr = (uint64_t)strtoll(str, &str2, 0);
if (*str2 != '\0') {
err_print("`%s' is not an integer.\n", str);
return (-1);
}
}
return (0);
}
static int
getbn(char *str, diskaddr_t *iptr)
{
char *cptr, *hptr, *sptr;
int cyl, head, sect;
int wild;
diskaddr_t wild64;
TOKEN buf;
cptr = str;
while ((*str != '\0') && (*str != '/'))
str++;
if (*str == '\0') {
wild64 = physsects() - 1;
if (geti64(cptr, iptr, &wild64))
return (-1);
return (0);
}
*str++ = '\0';
hptr = str;
while ((*str != '\0') && (*str != '/'))
str++;
if (*str == '\0')
sptr = str;
else {
*str++ = '\0';
sptr = str;
}
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 [0-%u].\n", cyl,
ncyl + acyl - 1);
return (-1);
}
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 [0-%u].\n", head, nhead - 1);
return (-1);
}
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 [0-%u].\n", sect,
sectors(head) - 1);
return (-1);
}
*iptr = chs2bn(cyl, head, sect);
return (0);
}
uint64_t
input(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;
if (type == FIO_OPINT) {
assert(deflt != NULL);
}
reprompt:
help = interactive = 0;
if (cmdflag == CMD_INPUT)
flushline();
if (!token_present)
interactive = 1;
fmt_print(promptstr);
if (deflt != NULL) {
switch (type) {
case FIO_BN:
#if !defined(lint)
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)
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:
s = find_string(param->io_slist, *deflt);
if (s == NULL) {
s = (param->io_slist)->str;
}
fmt_print("[%s]", s);
break;
case FIO_CYL:
blokno = *(blkaddr32_t *)deflt;
fmt_print("[%llub, %uc, %1.2fmb, %1.2fgb]", blokno,
bn2c(blokno), bn2mb(blokno), bn2gb(blokno));
break;
case FIO_ECYL:
part_deflt = (part_deflt_t *)deflt;
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)
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:
fmt_print("[default]");
break;
default:
err_print("Error: unknown input type.\n");
fullabort();
}
}
fmt_print("%c ", delim);
if (gettoken(token) == NULL)
fullabort();
if ((cmdflag == CMD_INPUT) && (token[0] == '!')) {
(void) memset(shell_argv, 0, sizeof (shell_argv));
arg = &token[1];
do {
if (*arg == '\0')
continue;
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);
(void) execute_shell(shell_argv, sizeof (shell_argv));
redisplay_menu_list((char **)param->io_charlist);
if (interactive) {
goto reprompt;
}
}
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);
}
}
if (!interactive || option_f) {
if (token2[0] == 0) {
fmt_print("%s\n", token);
} else {
fmt_print("%s %s\n", token, token2);
}
}
else if (log_file) {
log_print("%s %s\n", token, token2);
}
if (interactive && cmdflag != CMD_INPUT)
flushline();
clean_token(cleantoken, token);
if ((strcmp(cleantoken, "") == 0) && (type != FIO_BLNK)) {
if (deflt != NULL) {
if (type == FIO_OSTR) {
return ((int)alloc_string((char *)deflt));
} else if (type == FIO_SLIST) {
s = find_string(param->io_slist, *deflt);
if ((cur_label == L_TYPE_EFI) &&
(s == NULL)) {
return (*deflt);
}
if (s == NULL) {
return ((param->io_slist)->value);
} else {
return (*deflt);
}
} else if (type == FIO_OPINT) {
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 (interactive) {
goto reprompt;
}
err_print("No default for this entry.\n");
cmdabort(SIGINT);
}
if ((strcmp(cleantoken, "?") == 0) ||
(strcmp(cleantoken, "h") == 0) ||
(strcmp(cleantoken, "help") == 0)) {
help = 1;
}
switch (type) {
case FIO_BN:
bounds = (struct bounds *)¶m->io_bounds;
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;
}
if (cur_label == L_TYPE_EFI) {
if (geti64(cleantoken, (uint64_t *)&bn64, NULL))
break;
} else {
if (getbn(cleantoken, &bn64))
break;
}
if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
err_print("`");
pr_dblock(err_print, bn64);
err_print("' is out of range [%llu-%llu].\n",
bounds->lower, bounds->upper);
break;
}
return (bn64);
case FIO_INT:
bounds = (struct bounds *)¶m->io_bounds;
if (help) {
fmt_print("Expecting an integer from %llu",
bounds->lower);
fmt_print(" to %llu\n", bounds->upper);
break;
}
if (geti(cleantoken, (int *)&bn, NULL))
break;
if ((bn < bounds->lower) || (bn > bounds->upper)) {
err_print("`%lu' is out of range [%llu-%llu].\n", bn,
bounds->lower, bounds->upper);
break;
}
return (bn);
case FIO_INT64:
bounds = (struct bounds *)¶m->io_bounds;
if (help) {
fmt_print("Expecting an integer from %llu",
bounds->lower);
fmt_print(" to %llu\n", bounds->upper);
break;
}
if (geti64(cleantoken, (uint64_t *)&bn64, NULL)) {
break;
}
if ((bn64 < bounds->lower) || (bn64 > bounds->upper)) {
err_print("`%llu' is out of range [%llu-%llu].\n",
bn64, bounds->lower, bounds->upper);
break;
}
return (bn64);
case FIO_OPINT:
bounds = (struct bounds *)¶m->io_bounds;
if (help) {
fmt_print("Expecting an integer from %llu",
bounds->lower);
fmt_print(" to %llu, or no input\n", bounds->upper);
break;
}
if (geti(cleantoken, (int *)&bn, NULL))
break;
if ((bn < bounds->lower) || (bn > bounds->upper)) {
err_print("`%lu' is out of range [%llu-%llu].\n", bn,
bounds->lower, bounds->upper);
break;
}
if (!deflt)
*deflt = bn;
return (1);
case FIO_CSTR:
strings = (char **)param->io_charlist;
for (str = strings; *str != NULL; str++)
if (strcmp(cleantoken, *str) == 0)
return (str - strings);
if (help) {
print_input_choices(type, param);
} else {
err_print("`%s' is not expected.\n", cleantoken);
}
break;
case FIO_MSTR:
strings = (char **)param->io_charlist;
length = index = tied = 0;
for (str = strings; *str != NULL; str++) {
i = strcnt(cleantoken, *str);
if ((uint_t)i < strlen(cleantoken))
continue;
if (i == length)
tied = 1;
if (i > length) {
index = str - strings;
tied = 0;
length = i;
}
}
if (length == 0) {
if (help) {
print_input_choices(type, param);
} else {
err_print("`%s' is not expected.\n",
cleantoken);
}
break;
}
if (tied) {
err_print("`%s' is ambiguous.\n", cleantoken);
break;
}
return (index);
case FIO_OSTR:
if (help) {
fmt_print("Expecting a string\n");
break;
}
return ((int)alloc_string(token));
case FIO_BLNK:
nolog_print("\015");
if (log_file)
log_print("\n");
return (0);
case FIO_SLIST:
i = find_value((slist_t *)param->io_slist, cleantoken, &value);
if (i == 1) {
return (value);
} else {
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;
case FIO_CYL:
bounds = (struct bounds *)¶m->io_bounds;
assert(bounds->lower == 0);
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;
}
s = cleantoken;
while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
s++;
}
if (*s != 0) {
value = *s;
*s = 0;
} else {
value = cleantoken2[0];
}
if (strcmp(cleantoken, WILD_STRING) == 0) {
return (bounds->upper);
}
if (strcmp(cleantoken, "0") == 0) {
value = 'c';
}
if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
value = 'm';
}
switch (value) {
case 'b':
if (geti64(cleantoken, &bn64, &bounds->upper))
break;
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;
}
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':
i = bn2c(bounds->upper);
if (geti(cleantoken, &cyls, &i))
break;
if (cyls > (bounds->upper / spc())) {
err_print("`%dc' is out of range [0-%llu]\n",
cyls, bounds->upper / spc());
break;
}
return (cyls * spc());
case 'm':
if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
err_print("`%s' is not recognized\n",
cleantoken);
break;
}
if (nmegs > bn2mb(bounds->upper)) {
err_print("`%1.2fmb' is out of range "
"[0-%1.2f]\n", nmegs, bn2mb(bounds->upper));
break;
}
bn64 = mb2bn(nmegs);
i = spc();
bn64 = ((bn64 + (i-1)) / i) * i;
return (bn64);
case 'g':
if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
err_print("`%s' is not recognized\n",
cleantoken);
break;
}
if (ngigs > bn2gb(bounds->upper)) {
err_print("`%1.2fgb' is out of range "
"[0-%1.2f]\n", ngigs, bn2gb(bounds->upper));
break;
}
bn64 = gb2bn(ngigs);
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:
bounds = (struct bounds *)¶m->io_bounds;
assert(bounds->lower == 0);
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;
}
s = cleantoken;
while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
s++;
}
if (*s != 0) {
value = *s;
*s = 0;
} else {
value = cleantoken2[0];
}
if (strcmp(cleantoken, WILD_STRING) == 0) {
return (bounds->upper);
}
if (value != 'e' && strcmp(cleantoken, "0") == 0) {
value = 'c';
}
if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
value = 'm';
}
switch (value) {
case 'b':
if (geti64(cleantoken, &bn64, &bounds->upper))
break;
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;
}
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':
if (geti(cleantoken, &cylno, NULL)) {
break;
}
if (cylno < part_deflt->start_cyl) {
err_print(
"End cylinder must fall on or after start cylinder %u\n",
part_deflt->start_cyl);
break;
}
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;
}
cyls = ((cylno - part_deflt->start_cyl) + 1);
return (cyls * spc());
case 'c':
i = bn2c(bounds->upper);
if (geti(cleantoken, &cyls, &i))
break;
if (cyls > (bounds->upper / spc())) {
err_print("`%dc' is out of range [0-%llu]\n",
cyls, bounds->upper / spc());
break;
}
return (cyls * spc());
case 'm':
if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
err_print("`%s' is not recognized\n",
cleantoken);
break;
}
if (nmegs > bn2mb(bounds->upper)) {
err_print("`%1.2fmb' is out of range "
"[0-%1.2f]\n", nmegs, bn2mb(bounds->upper));
break;
}
bn64 = mb2bn(nmegs);
i = spc();
bn64 = ((bn64 + (i-1)) / i) * i;
return (bn64);
case 'g':
if (sscanf(cleantoken, "%f2", &ngigs) != 1) {
err_print("`%s' is not recognized\n",
cleantoken);
break;
}
if (ngigs > bn2gb(bounds->upper)) {
err_print("`%1.2fgb' is out of range "
"[0-%1.2f]\n", ngigs, bn2gb(bounds->upper));
break;
}
bn64 = gb2bn(ngigs);
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:
bounds = (struct bounds *)¶m->io_bounds;
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;
}
s = cleantoken;
while (*s && (isdigit(*s) || (*s == '.') || (*s == '$'))) {
s++;
}
if (*s != 0) {
value = *s;
*s = 0;
} else {
value = cleantoken2[0];
}
if (strcmp(cleantoken, WILD_STRING) == 0) {
uint64_t reserved;
reserved = efi_reserved_sectors(cur_parts->etoc);
return (bounds->upper - reserved -
efi_deflt->start_sector + 1);
}
if (value != 'e' && strcmp(cleantoken, "0") == 0) {
value = 'm';
}
if ((value == 0) && (strchr(cleantoken, '.') != NULL)) {
value = 'm';
}
switch (value) {
case 'b':
if (geti64(cleantoken, &blokno, 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':
if (geti64(cleantoken, &blokno, NULL)) {
break;
}
if (blokno < efi_deflt->start_sector) {
err_print("End Sector must fall on or after "
"start sector %llu\n",
efi_deflt->start_sector);
break;
}
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;
}
return (blokno - efi_deflt->start_sector + 1);
case 'm':
if (sscanf(cleantoken, "%f2", &nmegs) != 1) {
err_print("`%s' is not recognized\n",
cleantoken);
break;
}
if (nmegs > bn2mb(bounds->upper - bounds->lower)) {
err_print("`%1.2fmb' is out of range "
"[0-%1.2f]\n", nmegs,
bn2mb(bounds->upper - bounds->lower));
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 "
"[0-%1.2f]\n", nmegs,
bn2gb(bounds->upper - bounds->lower));
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 "
"[0-%1.2f]\n", nmegs,
bn2tb(bounds->upper - bounds->lower));
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;
default:
err_print("Error: unknown input type.\n");
fullabort();
}
if (option_f)
fullabort();
else if (interactive)
goto reprompt;
else
cmdabort(SIGINT);
return (-1);
}
static void
print_input_choices(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");
width = slist_widest_str((slist_t *)param->io_slist);
width += 4;
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 {
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");
}
int
find_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++) {
i = strcnt(match_str, slist->str);
if (i < match_length)
continue;
if (i == length)
nmatches++;
if (i > length) {
*match_value = slist->value;
nmatches = 1;
length = i;
}
}
return (nmatches);
}
char *
find_string(slist_t *slist, int match_value)
{
for (; slist->str != NULL; slist++) {
if (slist->value == match_value) {
return (slist->str);
}
}
return (NULL);
}
static int
slist_widest_str(slist_t *slist)
{
int i;
int width;
width = 0;
for (; slist->str != NULL; slist++) {
if ((i = strlen(slist->str)) > width)
width = i;
}
return (width);
}
static void
ljust_print(char *str, int width)
{
int i;
fmt_print("%s", str);
for (i = width - strlen(str); i > 0; i--) {
fmt_print(" ");
}
}
void
fmt_print(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (option_s == 0) {
if (need_newline) {
(void) printf("\n");
}
(void) vprintf(format, ap);
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);
}
void
nolog_print(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (option_s == 0) {
if (need_newline) {
(void) printf("\n");
}
(void) vprintf(format, ap);
}
va_end(ap);
need_newline = 0;
}
void
log_print(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (option_s == 0) {
if (need_newline) {
(void) fprintf(log_file, "\n");
}
(void) vfprintf(log_file, format, ap);
(void) fflush(log_file);
}
va_end(ap);
need_newline = 0;
}
void
err_print(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (need_newline) {
(void) printf("\n");
}
(void) fflush(stdout);
(void) vfprintf(stderr, format, ap);
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;
}
void
print_buf(char *buf, int nbytes)
{
int c;
while (nbytes-- > 0) {
c = *buf++;
if (isascii(c) && isprint(c)) {
fmt_print("%c", c);
} else
break;
}
}
#ifdef not
void
pr_ctlrline(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
void
pr_diskline(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
}
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);
}
}
static int
sup_inputchar(void)
{
int c;
c = getc(data_file);
if (c != '\\')
return (c);
c = getc(data_file);
if (c == '\n') {
data_lineno++;
c = getc(data_file);
}
return (c);
}
static void
sup_pushchar(int c)
{
(void) ungetc(c, data_file);
}
static int have_pushed_token = 0;
static TOKEN pushed_buf;
static int pushed_token;
int
sup_gettoken(char *buf)
{
last_token_type = sup_get_token(buf);
return (last_token_type);
}
static int
sup_get_token(char *buf)
{
char *ptr = buf;
int c, quoted = 0;
if (have_pushed_token) {
have_pushed_token = 0;
bcopy(pushed_buf, buf, TOKEN_SIZE+1);
return (pushed_token);
}
bzero(buf, TOKEN_SIZE + 1);
while ((isspace(c = sup_inputchar())) && (c != '\n'))
;
for (; !isspace(c) || quoted; c = sup_inputchar()) {
if (feof(data_file))
return (SUP_EOF);
if (c == '"') {
quoted = !quoted;
continue;
}
if (c == '\n')
break;
if (!quoted && (c == '=' || c == ',' || c == ':' ||
c == '#' || c == '|' || c == '&' || c == '~'))
break;
if (ptr - buf < TOKEN_SIZE)
*ptr++ = (char)c;
}
if (ptr - buf > 0) {
sup_pushchar(c);
return (SUP_STRING);
}
buf[0] = c;
switch (c) {
case '=':
return (SUP_EQL);
case ':':
return (SUP_COLON);
case ',':
return (SUP_COMMA);
case '\n':
return (SUP_EOL);
case '|':
return (SUP_OR);
case '&':
return (SUP_AND);
case '~':
return (SUP_TILDE);
case '#':
while ((c = sup_inputchar()) != '\n' && !feof(data_file))
;
if (feof(data_file))
return (SUP_EOF);
else
return (SUP_EOL);
default:
return (SUP_STRING);
}
}
void
sup_pushtoken(char *token_buf, int token_type)
{
assert(have_pushed_token == 0);
have_pushed_token = 1;
bcopy(token_buf, pushed_buf, TOKEN_SIZE+1);
pushed_token = token_type;
}
void
get_inputline(char *line, int nbytes)
{
char *p = line;
int c;
do {
while ((isspace(c = getchar())) && (c != '\n'))
;
} while (c == COMMENT_CHAR);
while (c != '\n') {
if (checkeof()) {
fullabort();
}
if (nbytes > 1) {
*p++ = (char)c;
nbytes --;
}
c = getchar();
}
*p = 0;
token_present = 0;
if (option_f) {
fmt_print("%s\n", line);
} else if (log_file) {
log_print("%s\n", line);
}
}
int
execute_shell(char *s, size_t buff_size)
{
struct termio termio;
struct termios tty;
int tty_flag, i, j;
char *shell_name;
static char *default_shell = "/bin/sh";
tty_flag = -1;
if (*s == '\0') {
shell_name = getenv("SHELL");
if (shell_name == NULL) {
shell_name = default_shell;
}
if (strlcpy(s, shell_name, buff_size) >=
buff_size) {
err_print("Error: Shell command ($SHELL) too long.\n");
fullabort();
}
}
if (isatty(0)) {
if (ioctl(0, TCGETS, &tty) == 0)
tty_flag = 1;
else {
if (ioctl(0, TCGETA, &termio) == 0) {
tty_flag = 0;
tty.c_iflag = termio.c_iflag;
tty.c_oflag = termio.c_oflag;
tty.c_cflag = termio.c_cflag;
tty.c_lflag = termio.c_lflag;
for (i = 0; i < NCC; i++)
tty.c_cc[i] = termio.c_cc[i];
}
}
}
if (cur_disk != NULL) {
(void) close(cur_file);
}
(void) system(s);
if (cur_disk != NULL) {
if ((cur_file = open_disk(cur_disk->disk_path,
O_RDWR | O_NDELAY)) < 0) {
err_print("Error: can't reopen selected disk '%s'. \n",
cur_disk->disk_name);
fullabort();
}
}
if (isatty(0)) {
if (tty_flag > 0)
(void) ioctl(0, TCSETSW, &tty);
else if (tty_flag == 0) {
termio.c_iflag = tty.c_iflag;
termio.c_oflag = tty.c_oflag;
termio.c_cflag = tty.c_cflag;
termio.c_lflag = tty.c_lflag;
for (j = 0; j < NCC; j++)
termio.c_cc[j] = tty.c_cc[j];
(void) ioctl(0, TCSETAW, &termio);
}
if (isatty(1)) {
fmt_print("\n[Hit Return to continue] \n");
(void) fflush(stdin);
if (getchar() == EOF)
fullabort();
}
}
return (0);
}
void
print_efi_string(char *vendor, char *product, char *revision,
uint64_t capacity)
{
char *new_vendor;
char *new_product;
char *new_revision;
char capacity_string[10];
float scaled;
int i;
new_vendor = strdup(vendor);
if (new_vendor == NULL)
return;
for (i = (strlen(new_vendor) - 1); i >= 0; i--) {
if (new_vendor[i] != 0x20) {
new_vendor[i+1] = '\0';
break;
}
}
new_product = strdup(product);
if (new_product == NULL) {
free(new_vendor);
return;
}
for (i = (strlen(new_product) - 1); i >= 0; i--) {
if (new_product[i] != 0x20) {
new_product[i+1] = '\0';
break;
}
}
new_revision = strdup(revision);
if (new_product == NULL) {
free(new_vendor);
free(new_product);
return;
}
for (i = (strlen(new_revision) - 1); i >= 0; i--) {
if (new_revision[i] != 0x20) {
new_revision[i+1] = '\0';
break;
}
}
scaled = bn2mb(capacity);
if (scaled >= (float)1024.0 * 1024) {
(void) snprintf(capacity_string, sizeof (capacity_string),
"%.2fTB", scaled/((float)1024.0 * 1024));
} else if (scaled >= (float)1024.0) {
(void) snprintf(capacity_string, sizeof (capacity_string),
"%.2fGB", scaled/(float)1024.0);
} else {
(void) snprintf(capacity_string, sizeof (capacity_string),
"%.2fMB", scaled);
}
fmt_print("<%s-%s-%s-%s>",
new_vendor, new_product, new_revision, capacity_string);
free(new_revision);
free(new_product);
free(new_vendor);
}