Files
scoutfs/utils/src/parse.c
Andy Grover 8f72d16609 scoutfs-utils: Use separate block devices for metadata and data
mkfs: Take two block devices as arguments. Write everything to metadata
dev, and the superblock to the data dev. UUIDs match. Differentiate by
checking a bit in a new "flags" field in the superblock.

Refactor device_size() a little. Convert spaces to tabs.

Move code to pretty-print sizes to dev.c so we can use it in error
messages there, as well as in mkfs.c.

print: Include flags in output.

Add -D and -M options for setting max dev sizes

Allow sizes to be specified using units like "K", "G" etc.

Note: -D option replaces -S option, and uses above units rather than
the number of 4k data blocks.

Update man pages for cmdline changes.

Signed-off-by: Andy Grover <agrover@versity.com>
2020-11-19 11:41:54 -08:00

155 lines
2.5 KiB
C

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include "sparse.h"
#include "util.h"
#include "format.h"
#include "parse.h"
/*
* Convert size with multiplicative suffix to bytes.
* e.g. "40M", "10G", "4T"
*
* These are powers-of-two prefixes - K means 1024 not 1000.
*
* One can go pretty far with variations but keeping relatively simple for
* now: commas, decimals, and multichar suffixes not handled.
*/
int parse_human(char* str, u64 *val_ret)
{
unsigned long long ull;
char *endptr = NULL;
int sh;
int ret = 0;
ull = strtoull(str, &endptr, 0);
if (((ull == LLONG_MIN || ull == LLONG_MAX) &&
errno == ERANGE)) {
fprintf(stderr, "invalid 64bit value: '%s'\n", str);
*val_ret = 0;
ret = -EINVAL;
goto error;
}
switch (*endptr) {
case 'K':
sh = 10;
break;
case 'M':
sh = 20;
break;
case 'G':
sh = 30;
break;
case 'T':
sh = 40;
break;
case 'P':
sh = 50;
break;
case '\0':
sh = 0;
break;
default:
fprintf(stderr, "unknown suffix: '%s'\n", endptr);
ret = -ERANGE;
goto error;
}
if (ull > (SIZE_MAX >> sh)) {
fprintf(stderr, "size too big: '%s'\n", str);
ret = -ERANGE;
goto error;
}
ull <<= sh;
*val_ret = ull;
error:
return ret;
}
int parse_u64(char *str, u64 *val_ret)
{
unsigned long long ull;
char *endptr = NULL;
ull = strtoull(str, &endptr, 0);
if (*endptr != '\0' ||
((ull == LLONG_MIN || ull == LLONG_MAX) &&
errno == ERANGE)) {
fprintf(stderr, "invalid 64bit value: '%s'\n", str);
*val_ret = 0;
return -EINVAL;
}
*val_ret = ull;
return 0;
}
int parse_s64(char *str, s64 *val_ret)
{
long long ll;
char *endptr = NULL;
ll = strtoll(str, &endptr, 0);
if (*endptr != '\0' ||
((ll == LLONG_MIN || ll == LLONG_MAX) &&
errno == ERANGE)) {
fprintf(stderr, "invalid 64bit value: '%s'\n", str);
*val_ret = 0;
return -EINVAL;
}
*val_ret = ll;
return 0;
}
int parse_u32(char *str, u32 *val_ret)
{
u64 val;
int ret;
ret = parse_u64(str, &val);
if (ret)
return ret;
if (val > UINT_MAX)
return -EINVAL;
*val_ret = val;
return 0;
}
int parse_timespec(char *str, struct timespec *ts)
{
unsigned long long sec;
unsigned int nsec;
int ret;
memset(ts, 0, sizeof(struct timespec));
ret = sscanf(str, "%llu.%u", &sec, &nsec);
if (ret != 2) {
fprintf(stderr, "invalid timespec string: '%s'\n", str);
return -EINVAL;
}
if (nsec > 1000000000) {
fprintf(stderr, "invalid timespec nsec value: '%s'\n", str);
return -EINVAL;
}
ts->tv_sec = sec;
ts->tv_nsec = nsec;
return 0;
}