btrfs-progs: configure: check if xmlto exists at configure time
[platform/upstream/btrfs-progs.git] / cmds-receive.c
index 68950b4..68123a3 100644 (file)
@@ -50,6 +50,7 @@
 #include "send-stream.h"
 #include "send-utils.h"
 #include "send-dump.h"
 #include "send-stream.h"
 #include "send-utils.h"
 #include "send-dump.h"
+#include "help.h"
 
 static int g_verbose = 0;
 
 
 static int g_verbose = 0;
 
@@ -287,13 +288,16 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
        parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid,
                                           parent_ctransid, NULL,
                                           subvol_search_by_received_uuid);
        parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid,
                                           parent_ctransid, NULL,
                                           subvol_search_by_received_uuid);
-       if (!parent_subvol) {
+       if (IS_ERR_OR_NULL(parent_subvol)) {
                parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid,
                                                   parent_ctransid, NULL,
                                                   subvol_search_by_uuid);
        }
                parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid,
                                                   parent_ctransid, NULL,
                                                   subvol_search_by_uuid);
        }
-       if (!parent_subvol) {
-               ret = -ENOENT;
+       if (IS_ERR_OR_NULL(parent_subvol)) {
+               if (!parent_subvol)
+                       ret = -ENOENT;
+               else
+                       ret = PTR_ERR(parent_subvol);
                error("cannot find parent subvolume");
                goto out;
        }
                error("cannot find parent subvolume");
                goto out;
        }
@@ -311,8 +315,8 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
                sub_len = strlen(parent_subvol->path);
 
                /* First make sure the parent subvol is actually in our path */
                sub_len = strlen(parent_subvol->path);
 
                /* First make sure the parent subvol is actually in our path */
-               if (sub_len < root_len ||
-                   strstr(parent_subvol->path, rctx->full_root_path) == NULL) {
+               if (strstr(parent_subvol->path, rctx->full_root_path) != parent_subvol->path ||
+                   (sub_len > root_len && parent_subvol->path[root_len] != '/')) {
                        error(
                "parent subvol is not reachable from inside the root subvol");
                        ret = -ENOENT;
                        error(
                "parent subvol is not reachable from inside the root subvol");
                        ret = -ENOENT;
@@ -320,7 +324,7 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
                }
 
                if (sub_len == root_len) {
                }
 
                if (sub_len == root_len) {
-                       parent_subvol->path[0] = '/';
+                       parent_subvol->path[0] = '.';
                        parent_subvol->path[1] = '\0';
                } else {
                        /*
                        parent_subvol->path[1] = '\0';
                } else {
                        /*
@@ -750,13 +754,16 @@ static int process_clone(const char *path, u64 offset, u64 len,
        si = subvol_uuid_search(&rctx->sus, 0, clone_uuid, clone_ctransid,
                                NULL,
                                subvol_search_by_received_uuid);
        si = subvol_uuid_search(&rctx->sus, 0, clone_uuid, clone_ctransid,
                                NULL,
                                subvol_search_by_received_uuid);
-       if (!si) {
+       if (IS_ERR_OR_NULL(si)) {
                if (memcmp(clone_uuid, rctx->cur_subvol.received_uuid,
                                BTRFS_UUID_SIZE) == 0) {
                        /* TODO check generation of extent */
                        subvol_path = strdup(rctx->cur_subvol_path);
                } else {
                if (memcmp(clone_uuid, rctx->cur_subvol.received_uuid,
                                BTRFS_UUID_SIZE) == 0) {
                        /* TODO check generation of extent */
                        subvol_path = strdup(rctx->cur_subvol_path);
                } else {
-                       ret = -ENOENT;
+                       if (!si)
+                               ret = -ENOENT;
+                       else
+                               ret = PTR_ERR(si);
                        error("clone: did not find source subvol");
                        goto out;
                }
                        error("clone: did not find source subvol");
                        goto out;
                }
@@ -776,7 +783,24 @@ static int process_clone(const char *path, u64 offset, u64 len,
                                                r->subvol_parent_name);
                        }
                }*/
                                                r->subvol_parent_name);
                        }
                }*/
-               subvol_path = strdup(si->path);
+
+               /* strip the subvolume that we are receiving to from the start of subvol_path */
+               if (rctx->full_root_path) {
+                       size_t root_len = strlen(rctx->full_root_path);
+                       size_t sub_len = strlen(si->path);
+
+                       if (sub_len > root_len &&
+                           strstr(si->path, rctx->full_root_path) == si->path &&
+                           si->path[root_len] == '/') {
+                               subvol_path = strdup(si->path + root_len + 1);
+                       } else {
+                               error("clone: source subvol path %s unreachable from %s",
+                                       si->path, rctx->full_root_path);
+                               goto out;
+                       }
+               } else {
+                       subvol_path = strdup(si->path);
+               }
        }
 
        ret = path_cat_out(full_clone_path, subvol_path, clone_path);
        }
 
        ret = path_cat_out(full_clone_path, subvol_path, clone_path);
@@ -1067,7 +1091,7 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt,
        char *dest_dir_full_path;
        char root_subvol_path[PATH_MAX];
        int end = 0;
        char *dest_dir_full_path;
        char root_subvol_path[PATH_MAX];
        int end = 0;
-       int count;
+       int iterations = 0;
 
        dest_dir_full_path = realpath(tomnt, NULL);
        if (!dest_dir_full_path) {
 
        dest_dir_full_path = realpath(tomnt, NULL);
        if (!dest_dir_full_path) {
@@ -1162,7 +1186,6 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt,
        if (ret < 0)
                goto out;
 
        if (ret < 0)
                goto out;
 
-       count = 0;
        while (!end) {
                if (rctx->cached_capabilities_len) {
                        if (g_verbose >= 3)
        while (!end) {
                if (rctx->cached_capabilities_len) {
                        if (g_verbose >= 3)
@@ -1176,22 +1199,28 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt,
                                                         rctx,
                                                         rctx->honor_end_cmd,
                                                         max_errors);
                                                         rctx,
                                                         rctx->honor_end_cmd,
                                                         max_errors);
-               if (ret < 0)
-                       goto out;
-               /* Empty stream is invalid */
-               if (ret && count == 0) {
-                       error("empty stream is not considered valid");
-                       ret = -EINVAL;
-                       goto out;
+               if (ret < 0) {
+                       if (ret != -ENODATA)
+                               goto out;
+
+                       /* Empty stream is invalid */
+                       if (iterations == 0) {
+                               error("empty stream is not considered valid");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = 1;
                }
                }
-               count++;
-               if (ret)
+               if (ret > 0)
                        end = 1;
 
                close_inode_for_write(rctx);
                ret = finish_subvol(rctx);
                if (ret < 0)
                        goto out;
                        end = 1;
 
                close_inode_for_write(rctx);
                ret = finish_subvol(rctx);
                if (ret < 0)
                        goto out;
+
+               iterations++;
        }
        ret = 0;
 
        }
        ret = 0;
 
@@ -1248,7 +1277,7 @@ int cmd_receive(int argc, char **argv)
                        { NULL, 0, NULL, 0 }
                };
 
                        { NULL, 0, NULL, 0 }
                };
 
-               c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
+               c = getopt_long(argc, argv, "Cevf:m:E:", long_opts, NULL);
                if (c < 0)
                        break;
 
                if (c < 0)
                        break;
 
@@ -1301,7 +1330,7 @@ int cmd_receive(int argc, char **argv)
        if (fromfile[0]) {
                receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
                if (receive_fd < 0) {
        if (fromfile[0]) {
                receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
                if (receive_fd < 0) {
-                       error("cannot open %s: %s", fromfile, strerror(errno));
+                       error("cannot open %s: %m", fromfile);
                        goto out;
                }
        }
                        goto out;
                }
        }
@@ -1330,36 +1359,32 @@ out:
 }
 
 const char * const cmd_receive_usage[] = {
 }
 
 const char * const cmd_receive_usage[] = {
-       "btrfs receive [options] <mount>",
-       "or",
+       "btrfs receive [options] <mount>\n"
        "btrfs receive --dump [options]",
        "btrfs receive --dump [options]",
-       "Receive subvolumes from stdin.",
+       "Receive subvolumes from a stream",
        "Receives one or more subvolumes that were previously",
        "sent with btrfs send. The received subvolumes are stored",
        "Receives one or more subvolumes that were previously",
        "sent with btrfs send. The received subvolumes are stored",
-       "into <mount>.",
-       "btrfs receive will fail in case a receiving subvolume",
+       "into MOUNT.",
+       "The receive will fail in case the receiving subvolume",
        "already exists. It will also fail in case a previously",
        "already exists. It will also fail in case a previously",
-       "received subvolume was changed after it was received.",
+       "received subvolume has been changed after it was received.",
        "After receiving a subvolume, it is immediately set to",
        "After receiving a subvolume, it is immediately set to",
-       "read only.\n",
-       "-v               Enable verbose debug output. Each",
-       "                 occurrence of this option increases the",
-       "                 verbose level more.",
-       "-f <infile>      By default, btrfs receive uses stdin",
-       "                 to receive the subvolumes. Use this",
-       "                 option to specify a file to use instead.",
-       "-e               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.",
+       "read-only.",
+       "",
+       "-v               increase verbosity about performed actions",
+       "-f FILE          read the stream from FILE instead of stdin",
+       "-e               terminate after receiving an <end cmd> marker in the stream.",
+       "                 Without this option the receiver side terminates only in case",
+       "                 of an error on end of file.",
        "-C|--chroot      confine the process to <mount> using chroot",
        "-C|--chroot      confine the process to <mount> using chroot",
-       "--max-errors <N> Terminate as soon as N errors happened while",
-       "                 processing commands from the send stream.",
+       "-E|--max-errors NERR",
+       "                 terminate as soon as NERR errors occur while",
+       "                 stream processing commands from the stream.",
        "                 Default value is 1. A value of 0 means no limit.",
        "                 Default value is 1. A value of 0 means no limit.",
-       "-m <mountpoint>  The root mount point of the destination fs.",
-       "                 If you do not have /proc use this to tell us where ",
+       "-m ROOTMOUNT     the root mount point of the destination filesystem.",
+       "                 If /proc is not accessible, use this to tell us where",
        "                 this file system is mounted.",
        "                 this file system is mounted.",
-       "--dump           Exam and output metadata info of send stream.",
-       "                 Don't need <mount> parameter.",
+       "--dump           dump stream metadata, one line per operation,",
+       "                 does not require the MOUNT parameter",
        NULL
 };
        NULL
 };