src/sbin/fdisk/misc.c

260 lines
5.2 KiB
C

/* $OpenBSD: misc.c,v 1.88 2022/07/10 20:34:31 krw Exp $ */
/*
* Copyright (c) 1997 Tobias Weingartner
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/disklabel.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "part.h"
#include "disk.h"
#include "misc.h"
const struct unit_type unit_types[] = {
{ "b" , 1LL , "Bytes" },
{ " " , 0LL , "Sectors" },
{ "K" , 1024LL , "Kilobytes" },
{ "M" , 1024LL * 1024 , "Megabytes" },
{ "G" , 1024LL * 1024 *1024 , "Gigabytes" },
{ "T" , 1024LL * 1024 * 1024 * 1024 , "Terabytes" },
};
#define SECTORS 1
double
units_size(const char *units, const uint64_t sectors,
const struct unit_type **ut)
{
double size;
unsigned int i;
*ut = &unit_types[SECTORS];
size = sectors;
for (i = 0; i < nitems(unit_types); i++) {
if (strncasecmp(unit_types[i].ut_abbr, units, 1) == 0)
*ut = &unit_types[i];
}
if ((*ut)->ut_conversion == 0)
return size;
else
return (size * dl.d_secsize) / (*ut)->ut_conversion;
}
void
string_from_line(char *buf, const size_t buflen, const int trim)
{
static char *line;
static size_t sz;
ssize_t len;
size_t n;
unsigned int i;
len = getline(&line, &sz, stdin);
if (len == -1)
errx(1, "eof");
switch (trim) {
case UNTRIMMED:
line[strcspn(line, "\n")] = '\0';
n = strlcpy(buf, line, buflen);
break;
case TRIMMED:
for (i = strlen(line); i > 0; i--) {
if (isspace((unsigned char)line[i - 1]) == 0)
break;
line[i - 1] = '\0';
}
n = strlcpy(buf, line + strspn(line, WHITESPACE), buflen);
break;
}
if (n >= buflen) {
printf("input too long\n");
memset(buf, 0, buflen);
}
}
int
ask_yn(const char *str)
{
int ch, first;
extern int y_flag;
if (y_flag)
return 1;
printf("%s [n] ", str);
fflush(stdout);
first = ch = getchar();
while (ch != '\n' && ch != EOF)
ch = getchar();
if (ch == EOF || first == EOF)
errx(1, "eof");
return first == 'y' || first == 'Y';
}
/*
* adapted from sbin/disklabel/editor.c
*/
uint64_t
getuint64(const char *prompt, uint64_t oval, const uint64_t minval,
const uint64_t maxval)
{
char buf[BUFSIZ], *endptr, *p, operator = '\0';
const int secsize = dl.d_secsize;
size_t n;
int64_t mult = 1;
double d, d2;
int rslt, secpercyl, saveerr;
char unit;
if (oval > maxval)
oval = maxval;
if (oval < minval)
oval = minval;
secpercyl = disk.dk_sectors * disk.dk_heads;
do {
printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval,
oval);
string_from_line(buf, sizeof(buf), TRIMMED);
if (buf[0] == '\0') {
rslt = snprintf(buf, sizeof(buf), "%llu", oval);
if (rslt < 0 || rslt >= sizeof(buf))
errx(1, "default value too long");
} else if (buf[0] == '*' && buf[1] == '\0') {
return maxval;
}
/* deal with units */
n = strlen(buf);
switch (tolower((unsigned char)buf[n-1])) {
case 'c':
unit = 'c';
mult = secpercyl;
buf[--n] = '\0';
break;
case 'b':
unit = 'b';
mult = -(int64_t)secsize;
buf[--n] = '\0';
break;
case 's':
unit = 's';
mult = 1;
buf[--n] = '\0';
break;
case 'k':
unit = 'k';
if (secsize > 1024)
mult = -(int64_t)secsize / 1024LL;
else
mult = 1024LL / secsize;
buf[--n] = '\0';
break;
case 'm':
unit = 'm';
mult = (1024LL * 1024) / secsize;
buf[--n] = '\0';
break;
case 'g':
unit = 'g';
mult = (1024LL * 1024 * 1024) / secsize;
buf[--n] = '\0';
break;
case 't':
unit = 't';
mult = (1024LL * 1024 * 1024 * 1024) / secsize;
buf[--n] = '\0';
break;
default:
unit = ' ';
mult = 1;
break;
}
/* deal with the operator */
p = &buf[0];
if (*p == '+' || *p == '-')
operator = *p++;
else
operator = ' ';
endptr = p;
errno = 0;
d = strtod(p, &endptr);
saveerr = errno;
d2 = d;
if (mult > 0)
d *= mult;
else {
d /= (-mult);
d2 = d;
}
/* Apply the operator */
if (operator == '+')
d = oval + d;
else if (operator == '-') {
d = oval - d;
d2 = d;
}
if (saveerr == ERANGE || d > maxval || d < minval || d < d2) {
printf("%s is out of range: %c%s%c\n", prompt, operator,
p, unit);
} else if (*endptr != '\0') {
printf("%s is invalid: %c%s%c\n", prompt, operator,
p, unit);
} else {
break;
}
} while (1);
return (uint64_t)d;
}
int
hex_octet(char *buf)
{
char *cp;
long num;
cp = buf;
num = strtol(buf, &cp, 16);
if (cp == buf || *cp != '\0')
return -1;
if (num < 0 || num > 0xff)
return -1;
return num;
}