summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/btrfs-receive.txt3
-rw-r--r--cmds-receive.c24
-rw-r--r--send-stream.c22
-rw-r--r--send-stream.h3
4 files changed, 42 insertions, 10 deletions
diff --git a/Documentation/btrfs-receive.txt b/Documentation/btrfs-receive.txt
index 82611603..78dc5116 100644
--- a/Documentation/btrfs-receive.txt
+++ b/Documentation/btrfs-receive.txt
@@ -38,6 +38,9 @@ Use this option to specify a file to use instead.
Terminate after receiving an <end cmd> in the data stream.
Without this option, the receiver terminates only if an error is recognized
or on EOF.
+--max-errors <N>::
+Terminate as soon as N errors happened while processing commands from the send
+stream. Default value is 1. A value of 0 means no limit.
EXIT STATUS
-----------
diff --git a/cmds-receive.c b/cmds-receive.c
index 8d85ca92..87dc1b4e 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -32,6 +32,7 @@
#include <ftw.h>
#include <wait.h>
#include <assert.h>
+#include <getopt.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -816,7 +817,8 @@ static struct btrfs_send_ops send_ops = {
.utimes = process_utimes,
};
-static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
+static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
+ u64 max_errors)
{
int ret;
char *dest_dir_full_path;
@@ -868,7 +870,8 @@ static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
while (!end) {
ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
- r->honor_end_cmd);
+ r->honor_end_cmd,
+ max_errors);
if (ret < 0)
goto out;
if (ret)
@@ -911,6 +914,11 @@ out:
return ret;
}
+static const struct option long_opts[] = {
+ { "max-errors", 1, NULL, 'E' },
+ { NULL, 0, NULL, 0 }
+};
+
int cmd_receive(int argc, char **argv)
{
int c;
@@ -918,7 +926,7 @@ int cmd_receive(int argc, char **argv)
char *fromfile = NULL;
struct btrfs_receive r;
int receive_fd = fileno(stdin);
-
+ u64 max_errors = 1;
int ret;
memset(&r, 0, sizeof(r));
@@ -926,7 +934,7 @@ int cmd_receive(int argc, char **argv)
r.write_fd = -1;
r.dest_dir_fd = -1;
- while ((c = getopt(argc, argv, "evf:")) != -1) {
+ while ((c = getopt_long(argc, argv, "evf:", long_opts, NULL)) != -1) {
switch (c) {
case 'v':
g_verbose++;
@@ -937,6 +945,9 @@ int cmd_receive(int argc, char **argv)
case 'e':
r.honor_end_cmd = 1;
break;
+ case 'E':
+ max_errors = arg_strtou64(optarg);
+ break;
case '?':
default:
fprintf(stderr, "ERROR: receive args invalid.\n");
@@ -957,7 +968,7 @@ int cmd_receive(int argc, char **argv)
}
}
- ret = do_receive(&r, tomnt, receive_fd);
+ ret = do_receive(&r, tomnt, receive_fd, max_errors);
return !!ret;
}
@@ -983,5 +994,8 @@ const char * const cmd_receive_usage[] = {
" in the data stream. Without this option,",
" the receiver terminates only if an error",
" is recognized or on EOF.",
+ "--max-errors <N> Terminate as soon as N errors happened while",
+ " processing commands from the send stream.",
+ " Default value is 1. A value of 0 means no limit.",
NULL
};
diff --git a/send-stream.c b/send-stream.c
index 88e18e2c..ef4d8899 100644
--- a/send-stream.c
+++ b/send-stream.c
@@ -435,13 +435,21 @@ out:
return ret;
}
+/*
+ * If max_errors is 0, then don't stop processing the stream if one of the
+ * callbacks in btrfs_send_ops structure returns an error. If greater than
+ * zero, stop after max_errors errors happened.
+ */
int btrfs_read_and_process_send_stream(int fd,
struct btrfs_send_ops *ops, void *user,
- int honor_end_cmd)
+ int honor_end_cmd,
+ u64 max_errors)
{
int ret;
struct btrfs_send_stream s;
struct btrfs_stream_header hdr;
+ u64 errors = 0;
+ int last_err = 0;
s.fd = fd;
s.ops = ops;
@@ -471,9 +479,12 @@ int btrfs_read_and_process_send_stream(int fd,
while (1) {
ret = read_and_process_cmd(&s);
- if (ret < 0)
- goto out;
- if (ret) {
+ if (ret < 0) {
+ last_err = ret;
+ errors++;
+ if (max_errors > 0 && errors >= max_errors)
+ goto out;
+ } else if (ret > 0) {
if (!honor_end_cmd)
ret = 0;
goto out;
@@ -481,5 +492,8 @@ int btrfs_read_and_process_send_stream(int fd,
}
out:
+ if (last_err && !ret)
+ ret = last_err;
+
return ret;
}
diff --git a/send-stream.h b/send-stream.h
index 17bc6692..293bf6af 100644
--- a/send-stream.h
+++ b/send-stream.h
@@ -58,7 +58,8 @@ struct btrfs_send_ops {
int btrfs_read_and_process_send_stream(int fd,
struct btrfs_send_ops *ops, void *user,
- int honor_end_cmd);
+ int honor_end_cmd,
+ u64 max_errors);
#ifdef __cplusplus
}