From 1e5cc26bdab34ed034bbfcdda7d235ccd05c453a Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 30 Apr 2026 16:14:38 -0700 Subject: [PATCH] Add scoutfs recompute-xattr-total subcommand. Wire SCOUTFS_IOC_RECOMPUTE_TOTL into the scoutfs util. Needs the path to the mountpoint the A.B.C totl key. Signed-off-by: Auke Kok --- utils/src/recompute_xattr_total.c | 129 ++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 utils/src/recompute_xattr_total.c diff --git a/utils/src/recompute_xattr_total.c b/utils/src/recompute_xattr_total.c new file mode 100644 index 00000000..06c35651 --- /dev/null +++ b/utils/src/recompute_xattr_total.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "parse.h" +#include "util.h" +#include "format.h" +#include "ioctl.h" +#include "cmd.h" + +struct recompute_xattr_total_args { + char *path; + u64 name[3]; + unsigned name_set:1; +}; + +/* parse ".." into name[0..2] */ +static int parse_dotted_name(const char *s, u64 name[3]) +{ + const char *p = s; + char *end; + int i; + + for (i = 0; i < 3; i++) { + if (*p == '\0' || *p == '.') + return -1; + errno = 0; + name[i] = strtoull(p, &end, 0); + if (errno || end == p) + return -1; + + if (i < 2) { + if (*end != '.') + return -1; + p = end + 1; + } else { + if (*end != '\0') + return -1; + } + } + return 0; +} + +static int do_recompute_xattr_total(struct recompute_xattr_total_args *args) +{ + struct scoutfs_ioctl_recompute_totl rt; + int ret; + int fd; + + fd = get_path(args->path, O_RDONLY); + if (fd < 0) + return fd; + + memset(&rt, 0, sizeof(rt)); + rt.name[0] = args->name[0]; + rt.name[1] = args->name[1]; + rt.name[2] = args->name[2]; + + ret = ioctl(fd, SCOUTFS_IOC_RECOMPUTE_TOTL, &rt); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "recompute_xattr_total ioctl failed: %s (%d)\n", + strerror(errno), errno); + } + + close(fd); + return ret; +} + +static int parse_opt(int key, char *arg, struct argp_state *state) +{ + struct recompute_xattr_total_args *args = state->input; + + switch (key) { + case 'p': + args->path = strdup_or_error(state, arg); + break; + case ARGP_KEY_ARG: + if (args->name_set) + argp_error(state, "more than one argument given"); + if (parse_dotted_name(arg, args->name)) + argp_error(state, "totl key parse error"); + args->name_set = 1; + break; + case ARGP_KEY_FINI: + if (!args->name_set) + argp_error(state, "must provide totl key"); + break; + default: + break; + } + + return 0; +} + +static struct argp_option options[] = { + { "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"}, + { NULL } +}; + +static struct argp argp = { + options, + parse_opt, + "A.B.C", + "Recompute a .totl. xattr key from its contributing xattrs and repair drift" +}; + +static int recompute_xattr_total_cmd(int argc, char **argv) +{ + struct recompute_xattr_total_args args = { 0 }; + int ret; + + ret = argp_parse(&argp, argc, argv, 0, NULL, &args); + if (ret) + return ret; + + return do_recompute_xattr_total(&args); +} + +static void __attribute__((constructor)) recompute_xattr_total_ctor(void) +{ + cmd_register_argp("recompute-xattr-total", &argp, GROUP_INFO, recompute_xattr_total_cmd); +}