mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-22 07:06:47 +00:00
Add punch-offline scoutfs subcommand.
A minimal punch_offline ioctl wrapper. Argument style is adopted from stage/release. Following the syntax for the option of stage/release, this calls the punch offline ioctl, punching any offline extent within the designated range from offset with length. Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "parse.h"
|
||||
#include "util.h"
|
||||
#include "ioctl.h"
|
||||
#include "cmd.h"
|
||||
|
||||
struct po_args {
|
||||
char *path;
|
||||
u64 offset;
|
||||
u64 length;
|
||||
u64 data_version;
|
||||
|
||||
unsigned offset_set:1,
|
||||
length_set:1,
|
||||
data_version_set:1;
|
||||
};
|
||||
|
||||
static int do_punch_offline(struct po_args *args)
|
||||
{
|
||||
struct scoutfs_ioctl_punch_offline ioctl_args;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
fd = get_path(args->path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ioctl_args.offset = args->offset;
|
||||
ioctl_args.len = args->length;
|
||||
ioctl_args.data_version = args->data_version;
|
||||
ioctl_args.flags = 0;
|
||||
|
||||
ret = ioctl(fd, SCOUTFS_IOC_PUNCH_OFFLINE, &ioctl_args);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "punch_offline 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 po_args *args = state->input;
|
||||
int ret = 0;
|
||||
|
||||
switch (key) {
|
||||
case 'V':
|
||||
ret = parse_u64(arg, &args->data_version);
|
||||
if (ret)
|
||||
return ret;
|
||||
args->data_version_set = 1;
|
||||
break;
|
||||
case 'o': /* offset */
|
||||
ret = parse_human(arg, &args->offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
args->offset_set = 1;
|
||||
break;
|
||||
case 'l': /* length */
|
||||
ret = parse_human(arg, &args->length);
|
||||
if (ret)
|
||||
return ret;
|
||||
args->length_set = 1;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (!args->path)
|
||||
args->path = strdup_or_error(state, arg);
|
||||
else
|
||||
argp_error(state, "unknown extra argument given");
|
||||
break;
|
||||
case ARGP_KEY_FINI:
|
||||
if (!args->path)
|
||||
argp_error(state, "must provide path to file");
|
||||
if (!args->offset_set)
|
||||
argp_error(state, "must provide offset");
|
||||
if (!args->length_set)
|
||||
argp_error(state, "must provide length");
|
||||
if (!args->data_version_set)
|
||||
argp_error(state, "must provide data_version");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "data-version", 'V', "VERSION", 0, "Data version of the file [Required]"},
|
||||
{ "offset", 'o', "OFFSET", 0, "Offset (bytes or KMGTP units) in file to stage [Required]"},
|
||||
{ "length", 'l', "LENGTH", 0, "Length of range (bytes or KMGTP units) of file to stage. [Required]"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct argp argp = {
|
||||
options,
|
||||
parse_opt,
|
||||
"PATH",
|
||||
"Make a (sparse) hole in the file at offset and with length"
|
||||
};
|
||||
|
||||
static int punch_offline_cmd(int argc, char **argv)
|
||||
{
|
||||
struct po_args po_args = {NULL};
|
||||
int ret;
|
||||
|
||||
ret = argp_parse(&argp, argc, argv, 0, NULL, &po_args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return do_punch_offline(&po_args);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) punch_offline_ctor(void)
|
||||
{
|
||||
cmd_register_argp("punch-offline", &argp, GROUP_AGENT, punch_offline_cmd);
|
||||
}
|
||||
Reference in New Issue
Block a user