From 97c6cc559e3eb799955a2d66e587b12da43cd946 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 3 Dec 2020 15:49:52 -0800 Subject: [PATCH] Implement argp support for data-waiting and data-wait-err These both have a lot of required options. Signed-off-by: Andy Grover --- utils/src/waiting.c | 274 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 216 insertions(+), 58 deletions(-) diff --git a/utils/src/waiting.c b/utils/src/waiting.c index 414a3c4c..35abdd8d 100644 --- a/utils/src/waiting.c +++ b/utils/src/waiting.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #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", " ", - "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 --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", " ", "return error from matching waiters", - data_wait_err_cmd); + wait_err_cmd); }