Implement argp support for setattr

Signed-off-by: Andy Grover <agrover@versity.com>
This commit is contained in:
Andy Grover
2020-12-03 13:57:26 -08:00
parent e1ba508301
commit 7c54c86c38

View File

@@ -7,8 +7,9 @@
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>
#include <argp.h>
#include <stdbool.h>
#include "sparse.h"
#include "util.h"
@@ -17,83 +18,41 @@
#include "parse.h"
#include "cmd.h"
static struct option long_ops[] = {
{ "ctime", 1, NULL, 'c' },
{ "data_version", 1, NULL, 'd' },
{ "file", 1, NULL, 'f' },
{ "offline", 0, NULL, 'o' },
{ "i_size", 1, NULL, 's' },
{ NULL, 0, NULL, 0}
struct setattr_args {
char *filename;
struct timespec ctime;
u64 data_version;
u64 i_size;
bool offline;
char __pad[7];
};
static int setattr_more_cmd(int argc, char **argv)
static int do_setattr(struct setattr_args *args)
{
struct scoutfs_ioctl_setattr_more sm;
struct timespec ctime;
char *path = NULL;
int ret;
struct scoutfs_ioctl_setattr_more sm = {0};
int fd = -1;
int c;
int ret;
memset(&sm, 0, sizeof(sm));
while ((c = getopt_long(argc, argv, "c:d:f:os:", long_ops, NULL)) != -1) {
switch (c) {
case 'c':
ret = parse_timespec(optarg, &ctime);
if (ret)
goto out;
break;
case 'd':
ret = parse_u64(optarg, &sm.data_version);
if (ret)
goto out;
break;
case 'f':
path = strdup(optarg);
if (!path) {
fprintf(stderr, "path mem alloc failed\n");
ret = -ENOMEM;
goto out;
}
break;
case 'o':
sm.flags |= SCOUTFS_IOC_SETATTR_MORE_OFFLINE;
break;
case 's':
ret = parse_u64(optarg, &sm.i_size);
if (ret)
goto out;
break;
case '?':
default:
ret = -EINVAL;
goto out;
}
}
if (path == NULL) {
fprintf(stderr, "must specify -f path to file\n");
ret = -EINVAL;
goto out;
}
fd = open(path, O_WRONLY);
fd = open(args->filename, O_WRONLY);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "failed to open '%s': %s (%d)\n",
path, strerror(errno), errno);
args->filename, strerror(errno), errno);
goto out;
}
sm.ctime_sec = ctime.tv_sec;
sm.ctime_nsec = ctime.tv_nsec;
sm.ctime_sec = args->ctime.tv_sec;
sm.ctime_nsec = args->ctime.tv_nsec;
sm.data_version = args->data_version;
if (args->offline)
sm.flags |= SCOUTFS_IOC_SETATTR_MORE_OFFLINE;
sm.i_size = args->i_size;
ret = ioctl(fd, SCOUTFS_IOC_SETATTR_MORE, &sm);
if (ret < 0) {
ret = -errno;
fprintf(stderr, "setattr_more ioctl failed on '%s': "
"%s (%d)\n", path, strerror(errno), errno);
"%s (%d)\n", args->filename, strerror(errno), errno);
goto out;
}
@@ -104,9 +63,84 @@ out:
return ret;
}
static int parse_opt(int key, char *arg, struct argp_state *state)
{
struct setattr_args *args = state->input;
int ret;
switch (key) {
case 't': /* timespec */
ret = parse_timespec(arg, &args->ctime);
if (ret)
return ret;
break;
case 'V': /* data version */
ret = parse_u64(arg, &args->data_version);
if (ret)
return ret;
if (args->data_version == 0)
argp_error(state, "data version must not be 0");
break;
case 's': /* size */
ret = parse_human(arg, &args->i_size);
if (ret)
return ret;
break;
case 'o': /* offline */
args->offline = true;
break;
case ARGP_KEY_ARG:
if (!args->filename)
args->filename = strdup_or_error(state, arg);
else
argp_error(state, "more than one argument given");
break;
case ARGP_KEY_FINI:
if (!args->filename)
argp_error(state, "no filename given");
if (args->i_size && !args->data_version) {
argp_error(state, "must provide data-version if using --size option");
}
if (!args->i_size && args->offline) {
argp_error(state, "must provide size if using --offline option");
}
break;
default:
break;
}
return 0;
}
static struct argp_option options[] = {
{ "ctime", 't', "TIMESPEC", 0, "Set creation time using \"<seconds-since-epoch>.<nanoseconds>\" format"},
{ "data-version", 'V', "VERSION", 0, "Set data version"},
{ "size", 's', "SIZE", 0, "Set file size (bytes or KMGTP units). Requires --data-version"},
{ "offline", 'o', NULL, 0, "Set file contents as offline, not sparse. Requires --size"},
{ NULL }
};
static int setattr_cmd(int argc, char **argv)
{
struct argp argp = {
options,
parse_opt,
"FILE",
"Set attributes on newly-created zero-length file"
};
struct setattr_args setattr_args = {NULL};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &setattr_args);
if (ret)
return ret;
return do_setattr(&setattr_args);
}
static void __attribute__((constructor)) setattr_more_ctor(void)
{
cmd_register("setattr", "-c ctime -d data_version -o -s i_size -f <path>",
"set attributes on file with no data",
setattr_more_cmd);
cmd_register("setattr", "<path>",
"set attributes on newly-created zero-length file",
setattr_cmd);
}