From: Darrick J. Wong <djwong@xxxxxxxxxx> Add some new subcommands to xfs_io so that users can administer filesystem properties. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>Acked-by: Dave Chinner <dchinner@xxxxxxxxxx> --- io/Makefile | 1 io/fsproperties.c | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 io/io.h | 1 man/man8/xfs_io.8 | 16 ++ 5 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 io/fsproperties.c diff --git a/io/Makefile b/io/Makefile index 3192b813c..0bdd05b57 100644 --- a/io/Makefile +++ b/io/Makefile @@ -20,6 +20,7 @@ CFILES = \ fiemap.c \ file.c \ freeze.c \ + fsproperties.c \ fsuuid.c \ fsync.c \ getrusage.c \ diff --git a/io/fsproperties.c b/io/fsproperties.c new file mode 100644 index 000000000..79837132e --- /dev/null +++ b/io/fsproperties.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@xxxxxxxxxx> + */ +#include "platform_defs.h" +#include "command.h" +#include "init.h" +#include "libfrog/paths.h" +#include "input.h" +#include "libfrog/fsgeom.h" +#include "handle.h" +#include "io.h" +#include "libfrog/fsprops.h" +#include "libfrog/fsproperties.h" + +static void +listfsprops_help(void) +{ + printf(_( +"Print the names of the filesystem properties stored in this filesystem.\n" +"\n")); +} + +static int +fileio_to_fsprops_handle( + struct fileio *file, + struct fsprops_handle *fph) +{ + struct xfs_fd xfd = XFS_FD_INIT(file->fd); + struct fs_path *fs; + void *hanp = NULL; + size_t hlen; + int ret; + + /* + * Look up the mount point info for the open file, which confirms that + * we were passed a mount point. + */ + fs = fs_table_lookup(file->name, FS_MOUNT_POINT); + if (!fs) { + fprintf(stderr, _("%s: Not a XFS mount point.\n"), + file->name); + goto bad; + } + + /* + * Register the mountpoint in the fsfd cache so we can use handle + * functions later. + */ + ret = path_to_fshandle(fs->fs_dir, &hanp, &hlen); + if (ret) { + perror(fs->fs_dir); + goto bad; + } + + ret = -xfd_prepare_geometry(&xfd); + if (ret) { + perror(file->name); + goto free_handle; + } + + ret = fsprops_open_handle(&xfd, &file->fs_path, fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, _("%s: Not a XFS mount point.\n"), + file->name); + else + perror(file->name); + goto free_handle; + } + + free_handle(hanp, hlen); + return 0; +free_handle: + free_handle(hanp, hlen); +bad: + exitcode = 1; + return 1; +} + +static int +print_fsprop( + struct fsprops_handle *fph, + const char *name, + size_t unused, + void *priv) +{ + bool *print_values = priv; + char valuebuf[FSPROP_MAX_VALUELEN]; + size_t valuelen = FSPROP_MAX_VALUELEN; + int ret; + + if (!(*print_values)) { + printf("%s\n", name); + return 0; + } + + ret = fsprops_get(fph, name, valuebuf, &valuelen); + if (ret) + return ret; + + printf("%s=%.*s\n", name, (int)valuelen, valuebuf); + return 0; +} + +static int +listfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + bool print_values = false; + int c; + int ret; + + while ((c = getopt(argc, argv, "v")) != EOF) { + switch (c) { + case 'v': + print_values = true; + break; + default: + exitcode = 1; + listfsprops_help(); + return 0; + } + } + + ret = fileio_to_fsprops_handle(file, &fph); + if (ret) + return 1; + + ret = fsprops_walk_names(&fph, print_fsprop, &print_values); + if (ret) { + perror(file->name); + exitcode = 1; + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo listfsprops_cmd = { + .name = "listfsprops", + .cfunc = listfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_NOMAP_OK, + .args = "", + .help = listfsprops_help, +}; + +static void +getfsprops_help(void) +{ + printf(_( +"Print the values of filesystem properties stored in this filesystem.\n" +"\n" +"Pass property names as the arguments.\n" +"\n")); +} + +static int +getfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + int c; + int ret; + + while ((c = getopt(argc, argv, "")) != EOF) { + switch (c) { + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + for (c = optind; c < argc; c++) { + char valuebuf[FSPROP_MAX_VALUELEN]; + size_t valuelen = FSPROP_MAX_VALUELEN; + + ret = fsprops_get(&fph, argv[c], valuebuf, &valuelen); + if (ret) { + perror(argv[c]); + exitcode = 1; + break; + } + + printf("%s=%.*s\n", argv[c], (int)valuelen, valuebuf); + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo getfsprops_cmd = { + .name = "getfsprops", + .cfunc = getfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_NOMAP_OK, + .args = "", + .help = getfsprops_help, +}; + +static void +setfsprops_help(void) +{ + printf(_( +"Set values of filesystem properties stored in this filesystem.\n" +"\n" +" -f Do not try to validate property value.\n" +"\n" +"Provide name=value tuples as the arguments.\n" +"\n")); +} + +static int +setfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + bool force = false; + int c; + int ret; + + while ((c = getopt(argc, argv, "f")) != EOF) { + switch (c) { + case 'f': + force = true; + break; + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + for (c = optind; c < argc; c ++) { + char *equals = strchr(argv[c], '='); + + if (!equals) { + fprintf(stderr, _("%s: property value required.\n"), + argv[c]); + exitcode = 1; + break; + } + + *equals = 0; + + if (!force && !fsprop_validate(argv[c], equals + 1)) { + fprintf(stderr, _("%s: invalid value \"%s\".\n"), + argv[c], equals + 1); + *equals = '='; + exitcode = 1; + break; + } + + ret = fsprops_set(&fph, argv[c], equals + 1, + strlen(equals + 1)); + if (ret) { + perror(argv[c]); + *equals = '='; + exitcode = 1; + break; + } + + printf("%s=%s\n", argv[c], equals + 1); + *equals = '='; + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo setfsprops_cmd = { + .name = "setfsprops", + .cfunc = setfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_NOMAP_OK, + .args = "", + .help = setfsprops_help, +}; + +static void +removefsprops_help(void) +{ + printf(_( +"Unset a filesystem property.\n" +"\n" +"Pass property names as the arguments.\n" +"\n")); +} + +static int +removefsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + int c; + int ret; + + while ((c = getopt(argc, argv, "")) != EOF) { + switch (c) { + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + for (c = optind; c < argc; c++) { + ret = fsprops_remove(&fph, argv[c]); + if (ret) { + perror(argv[c]); + exitcode = 1; + break; + } + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo removefsprops_cmd = { + .name = "removefsprops", + .cfunc = removefsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_NOMAP_OK, + .args = "", + .help = removefsprops_help, +}; + +void +fsprops_init(void) +{ + listfsprops_cmd.oneline = _("list file system properties"); + getfsprops_cmd.oneline = _("print file system properties"); + setfsprops_cmd.oneline = _("set file system properties"); + removefsprops_cmd.oneline = _("unset file system properties"); + + add_command(&listfsprops_cmd); + add_command(&getfsprops_cmd); + add_command(&setfsprops_cmd); + add_command(&removefsprops_cmd); +} diff --git a/io/init.c b/io/init.c index 37e0f093c..5727f7351 100644 --- a/io/init.c +++ b/io/init.c @@ -89,6 +89,7 @@ init_commands(void) utimes_init(); crc32cselftest_init(); exchangerange_init(); + fsprops_init(); } /* diff --git a/io/io.h b/io/io.h index fdb715ff0..8c5e59100 100644 --- a/io/io.h +++ b/io/io.h @@ -150,3 +150,4 @@ extern void repair_init(void); extern void crc32cselftest_init(void); extern void bulkstat_init(void); void exchangerange_init(void); +void fsprops_init(void); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 657bdaec4..303c64478 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1578,7 +1578,21 @@ Print the sysfs or debugfs path for the mounted filesystem. The .B -d option selects debugfs instead of sysfs. - +.TP +.BI "getfsprops " name " [ " names "... ]" +Retrieve the values of the given filesystem properties. +.TP +.BI "listfsprops [ " \-v " ]" +List all filesystem properties that have been stored in the filesystem. +If the +.B \-v +flag is specified, prints the values of the properties. +.TP +.BI "setfsprops " name = value " [ " name = value "... ]" +Set the given filesystem properties to the specified values. +.TP +.BI "removefsprops " name " [ " names "... ]" +Remove the given filesystem properties. .SH OTHER COMMANDS .TP