mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-10 12:40:09 +00:00
Make it static and then use it both for argp_parse as well as cmd_register_argp. Split commands into five groups, to help understanding of their usefulness. Mention that each command has its own help text, and that we are being fancy to keep the user from having to give fs path. Signed-off-by: Andy Grover <agrover@versity.com>
214 lines
4.4 KiB
C
214 lines
4.4 KiB
C
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <argp.h>
|
|
|
|
#include "sparse.h"
|
|
#include "parse.h"
|
|
#include "util.h"
|
|
#include "format.h"
|
|
#include "ioctl.h"
|
|
#include "cmd.h"
|
|
|
|
/*
|
|
* Parse the command line specification of a walk inodes entry of the
|
|
* form "major.minor.ino". At least one value must be given, the rest
|
|
* default to 0.
|
|
*/
|
|
static int parse_walk_entry(struct scoutfs_ioctl_walk_inodes_entry *ent,
|
|
char *str)
|
|
{
|
|
char *endptr;
|
|
char *c;
|
|
u64 ull;
|
|
u64 minor = 0;
|
|
u64 *val;
|
|
|
|
memset(ent, 0, sizeof(*ent));
|
|
val = &ent->major;
|
|
|
|
for (;;) {
|
|
c = index(str, '.');
|
|
if (c)
|
|
*c = '\0';
|
|
|
|
endptr = NULL;
|
|
ull = strtoull(str, &endptr, 0);
|
|
if (*endptr != '\0' ||
|
|
((ull == LLONG_MIN || ull == LLONG_MAX) &&
|
|
errno == ERANGE) ||
|
|
(val == &minor && (*val < INT_MIN || *val > INT_MAX))) {
|
|
fprintf(stderr, "bad index pos at '%s'\n", str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
*val = ull;
|
|
|
|
if (val == &ent->major)
|
|
val = &minor;
|
|
else if (val == &minor)
|
|
val = &ent->ino;
|
|
else
|
|
break;
|
|
|
|
if (c)
|
|
str = c + 1;
|
|
else
|
|
break;
|
|
}
|
|
|
|
ent->minor = minor;
|
|
return 0;
|
|
}
|
|
|
|
struct walk_inodes_args {
|
|
char *path;
|
|
char *index;
|
|
char *first_entry;
|
|
char *last_entry;
|
|
};
|
|
|
|
static int do_walk_inodes(struct walk_inodes_args *args)
|
|
{
|
|
struct scoutfs_ioctl_walk_inodes_entry ents[128];
|
|
struct scoutfs_ioctl_walk_inodes walk;
|
|
u64 total = 0;
|
|
int ret;
|
|
int fd;
|
|
int i;
|
|
|
|
if (!strcasecmp(args->index, "meta_seq"))
|
|
walk.index = SCOUTFS_IOC_WALK_INODES_META_SEQ;
|
|
else if (!strcasecmp(args->index, "data_seq"))
|
|
walk.index = SCOUTFS_IOC_WALK_INODES_DATA_SEQ;
|
|
else {
|
|
fprintf(stderr, "unknown index '%s', try 'meta_seq' or "
|
|
"'data_seq'\n", args->index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = parse_walk_entry(&walk.first, args->first_entry);
|
|
if (ret) {
|
|
fprintf(stderr, "invalid first position '%s', try '1.2.3' or "
|
|
"'-1'\n", args->first_entry);
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
ret = parse_walk_entry(&walk.last, args->last_entry);
|
|
if (ret) {
|
|
fprintf(stderr, "invalid last position '%s', try '1.2.3' or "
|
|
"'-1'\n", args->last_entry);
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
fd = get_path(args->path, O_RDONLY);
|
|
if (fd < 0)
|
|
return fd;
|
|
|
|
walk.entries_ptr = (unsigned long)ents;
|
|
walk.nr_entries = array_size(ents);
|
|
|
|
for (;;) {
|
|
ret = ioctl(fd, SCOUTFS_IOC_WALK_INODES, &walk);
|
|
if (ret < 0) {
|
|
ret = -errno;
|
|
fprintf(stderr, "walk_inodes ioctl failed: %s (%d)\n",
|
|
strerror(errno), errno);
|
|
break;
|
|
} else if (ret == 0) {
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < ret; i++) {
|
|
if ((total + i) % 25 == 0)
|
|
printf("%-20s %-20s %-10s %-20s\n",
|
|
"#", "major", "minor", "ino");
|
|
|
|
printf("%-20llu %-20llu %-10u %-20llu\n",
|
|
total + i, ents[i].major, ents[i].minor,
|
|
ents[i].ino);
|
|
}
|
|
|
|
total += i;
|
|
|
|
walk.first = ents[i - 1];
|
|
if (++walk.first.ino == 0 && ++walk.first.minor == 0)
|
|
walk.first.major++;
|
|
}
|
|
|
|
close(fd);
|
|
return ret;
|
|
};
|
|
|
|
static int walk_inodes_parse_opt(int key, char *arg, struct argp_state *state)
|
|
{
|
|
struct walk_inodes_args *args = state->input;
|
|
|
|
switch (key) {
|
|
case 'p':
|
|
args->path = strdup_or_error(state, arg);
|
|
break;
|
|
case ARGP_KEY_ARG:
|
|
if (!args->index)
|
|
args->index = strdup_or_error(state, arg);
|
|
else if (!args->first_entry)
|
|
args->first_entry = strdup_or_error(state, arg);
|
|
else if (!args->last_entry)
|
|
args->last_entry = strdup_or_error(state, arg);
|
|
else
|
|
argp_error(state, "more than three arguments given");
|
|
break;
|
|
case ARGP_KEY_FINI:
|
|
if (!args->index)
|
|
argp_error(state, "no index given");
|
|
if (!args->first_entry)
|
|
argp_error(state, "no first entry given");
|
|
if (!args->last_entry)
|
|
argp_error(state, "no last entry given");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct argp_option options[] = {
|
|
{ "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"},
|
|
{ NULL }
|
|
};
|
|
|
|
static struct argp argp = {
|
|
options,
|
|
walk_inodes_parse_opt,
|
|
"<meta_seq|data_seq> FIRST-ENTRY LAST-ENTRY",
|
|
"Print range of indexed inodes"
|
|
};
|
|
|
|
static int walk_inodes_cmd(int argc, char **argv)
|
|
{
|
|
struct walk_inodes_args walk_inodes_args = {NULL};
|
|
int ret;
|
|
|
|
ret = argp_parse(&argp, argc, argv, 0, NULL, &walk_inodes_args);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return do_walk_inodes(&walk_inodes_args);
|
|
}
|
|
|
|
|
|
static void __attribute__((constructor)) walk_inodes_ctor(void)
|
|
{
|
|
cmd_register_argp("walk-inodes", &argp, GROUP_SEARCH, walk_inodes_cmd);
|
|
}
|