Implement argp support for data-waiting and data-wait-err

These both have a lot of required options.

Signed-off-by: Andy Grover <agrover@versity.com>
This commit is contained in:
Andy Grover
2021-01-12 16:29:42 -08:00
parent 7c54c86c38
commit 97c6cc559e
+216 -58
View File
@@ -8,6 +8,8 @@
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <argp.h>
#include <stdbool.h>
#include "sparse.h"
#include "util.h"
@@ -31,7 +33,16 @@
(((ops) & (bit)) ? (str) : ""), \
(((ops) & (bit)) && ((ops) & ~(((bit) << 1) - 1)) ? "," : "")
static int waiting_cmd(int argc, char **argv)
struct waiting_args {
char *path;
bool inode_set;
u64 inode;
bool blkno_set;
u64 blkno;
};
static int do_waiting(struct waiting_args *args)
{
struct scoutfs_ioctl_data_waiting_entry dwe[16];
struct scoutfs_ioctl_data_waiting idw;
@@ -39,25 +50,13 @@ static int waiting_cmd(int argc, char **argv)
int fd;
int i;
if (argc != 4) {
fprintf(stderr, "must specify ino, iblock, and path\n");
return -EINVAL;
}
ret = parse_u64(argv[1], &idw.after_ino) ?:
parse_u64(argv[2], &idw.after_iblock);
if (ret)
return ret;
fd = open(argv[3], O_RDONLY);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "failed to open '%s': %s (%d)\n",
argv[3], strerror(errno), errno);
return ret;
}
fd = get_path(args->path, O_RDONLY);
if (fd < 0)
return fd;
idw.flags = 0;
idw.after_ino = args->inode;
idw.after_iblock = args->blkno;
idw.ents_ptr = (unsigned long)dwe;
idw.ents_nr = array_size(dwe);
@@ -91,59 +90,114 @@ static int waiting_cmd(int argc, char **argv)
return ret;
};
static void __attribute__((constructor)) waiting_ctor(void)
static int waiting_parse_opt(int key, char *arg, struct argp_state *state)
{
cmd_register("data-waiting", "<ino> <iblock> <path>",
"print ops waiting for data blocks", waiting_cmd);
}
static int data_wait_err_cmd(int argc, char **argv)
{
struct scoutfs_ioctl_data_wait_err args;
int fd = -1;
struct waiting_args *args = state->input;
int ret;
memset(&args, 0, sizeof(args));
if (argc != 8) {
fprintf(stderr, "must specify path, ino, version, offset, count,op, and err\n");
return -EINVAL;
switch (key) {
case 'p':
args->path = strdup_or_error(state, arg);
break;
case 'I': /* inode */
ret = parse_u64(arg, &args->inode);
if (ret)
argp_error(state, "inode parse error");
args->inode_set = true;
break;
case 'B': /* blkno */
ret = parse_u64(arg, &args->blkno);
if (ret)
argp_error(state, "blkno parse error");
args->blkno_set = true;
break;
case ARGP_KEY_FINI:
if (!args->inode_set)
argp_error(state, "no inode given");
if (!args->blkno_set)
argp_error(state, "no blkno given");
break;
default:
break;
}
ret = parse_u64(argv[2], &args.ino) ?:
parse_u64(argv[3], &args.data_version) ?:
parse_u64(argv[4], &args.offset) ?:
parse_u64(argv[5], &args.count) ?:
parse_s64(argv[7], &args.err);
return 0;
}
static struct argp_option waiting_options[] = {
{ "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"},
{ "inode", 'I', "INODE-NUM", 0, "Inode number [Required]"},
{ "block", 'B', "BLKNO-NUM", 0, "Block number [Required]"},
{ NULL }
};
static int waiting_cmd(int argc, char **argv)
{
struct argp argp = {
waiting_options,
waiting_parse_opt,
"--inode INODE-NUM --block BLOCK-NUM",
"Print operations waiting for data blocks"
};
struct waiting_args waiting_args = {NULL};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &waiting_args);
if (ret)
return ret;
if ((args.err >= 0) || (args.err < -MAX_ERRNO)) {
fprintf(stderr, "err %lld invalid\n", args.err);
ret = -EINVAL;
goto out;
}
return do_waiting(&waiting_args);
}
if (!strcmp(argv[6], "read")) {
args.op = SCOUTFS_IOC_DWO_READ;
} else if (!strcmp(argv[6], "write")) {
args.op = SCOUTFS_IOC_DWO_WRITE;
} else if (!strcmp(argv[6], "change_size")) {
args.op = SCOUTFS_IOC_DWO_CHANGE_SIZE;
static void __attribute__((constructor)) waiting_ctor(void)
{
cmd_register("data-waiting", "--inode <inode> --blockno <blockno>",
"print ops waiting for data blocks", waiting_cmd);
}
struct wait_err_args {
char *path;
bool inode_set;
u64 inode;
bool version_set;
u64 version;
bool offset_set;
u64 offset;
bool count_set;
u64 count;
char *op;
bool err_set;
s64 err;
};
static int do_wait_err(struct wait_err_args *args)
{
struct scoutfs_ioctl_data_wait_err dwe = {0};
int fd = -1;
int ret;
dwe.ino = args->inode;
dwe.data_version = args->version;
dwe.offset = args->offset;
dwe.count = args->count;
if (!strcmp(args->op, "read")) {
dwe.op = SCOUTFS_IOC_DWO_READ;
} else if (!strcmp(args->op, "write")) {
dwe.op = SCOUTFS_IOC_DWO_WRITE;
} else if (!strcmp(args->op, "change_size")) {
dwe.op = SCOUTFS_IOC_DWO_CHANGE_SIZE;
} else {
fprintf(stderr, "invalid data wait op: '%s'\n", argv[6]);
fprintf(stderr, "invalid data wait op: '%s'\n", args->op);
return -EINVAL;
}
dwe.err = args->err;
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "failed to open '%s': %s (%d)\n",
argv[1], strerror(errno), errno);
return ret;
}
fd = get_path(args->path, O_RDONLY);
if (fd < 0)
return fd;
ret = ioctl(fd, SCOUTFS_IOC_DATA_WAIT_ERR, &args);
ret = ioctl(fd, SCOUTFS_IOC_DATA_WAIT_ERR, &dwe);
if (ret < 0) {
fprintf(stderr, "data_wait_err returned %d: error %s (%d)\n",
ret, strerror(errno), errno);
@@ -158,9 +212,113 @@ out:
return ret;
};
static int wait_err_parse_opt(int key, char *arg, struct argp_state *state)
{
struct wait_err_args *args = state->input;
int ret;
switch (key) {
case 'p':
args->path = strdup_or_error(state, arg);
break;
case 'I': /* inode */
ret = parse_u64(arg, &args->inode);
if (ret)
argp_error(state, "inode parse error");
args->inode_set = true;
break;
case 'V': /* version */
ret = parse_u64(arg, &args->version);
if (ret)
argp_error(state, "version parse error");
args->version_set = true;
break;
case 'F': /* offset */
ret = parse_human(arg, &args->offset);
if (ret)
argp_error(state, "version parse error");
args->offset_set = true;
break;
case 'C': /* count */
ret = parse_u64(arg, &args->count);
if (ret)
argp_error(state, "count parse error");
args->count_set = true;
break;
case 'O': /* op */
args->op = strdup_or_error(state, arg);
break;
case 'E': /* err */
ret = parse_s64(arg, &args->err);
if (ret)
argp_error(state, "error parse error");
if ((args->err >= 0) || (args->err < -MAX_ERRNO))
argp_error(state, "errno out of range");
args->err_set = true;
break;
case ARGP_KEY_FINI:
if (!args->inode_set)
argp_error(state, "no inode given");
if (!args->version_set)
argp_error(state, "no version given");
if (!args->offset_set)
argp_error(state, "no offset given");
if (!args->count_set)
argp_error(state, "no count given");
if (!args->op)
argp_error(state, "no operation given");
if (!args->err_set)
argp_error(state, "no error given");
break;
default:
break;
}
return 0;
}
static struct argp_option wait_err_options[] = {
{ "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"},
{ "inode", 'I', "INODE-NUM", 0, "Inode number [Required]"},
{ "version", 'V', "VER-NUM", 0, "Version [Required]"},
{ "offset", 'F', "OFF-NUM", 0, "Offset (bytes or KMGTP units) [Required]"},
{ "count", 'C', "COUNT", 0, "Count [Required]"},
{ "op", 'O', "OP", 0, "Operation: \"read\", \"write\", \"change_size\" [Required]"},
{ "err", 'E', "ERR", 0, "Error [Required]"},
{ NULL }
};
static struct argp wait_err_argp = {
wait_err_options,
wait_err_parse_opt,
"--inode INODE-NUM --version VER-NUM "
"--offset OFF-NUM --count COUNT --op OP --err ERR",
"Return error from matching waiters"
};
static int wait_err_cmd(int argc, char **argv)
{
struct argp argp = {
wait_err_options,
wait_err_parse_opt,
"--inode INODE-NUM --block BLOCK-NUM --version VER-NUM "
"--offset OFF-NUM --count COUNT --op OP --err ERR",
"Return error from matching waiters"
};
struct wait_err_args wait_err_args = {NULL};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &wait_err_args);
if (ret)
return ret;
return do_wait_err(&wait_err_args);
}
static void __attribute__((constructor)) data_wait_err_ctor(void)
{
cmd_register("data-wait-err", "<path> <ino> <vers> <offset> <count> <op> <err>",
"return error from matching waiters",
data_wait_err_cmd);
wait_err_cmd);
}