2 * Copyright (C) 2012 Alexander Block. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
19 #include "kerncompat.h"
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
36 #include <sys/types.h>
37 #include <sys/xattr.h>
38 #include <uuid/uuid.h>
45 #include "btrfs-list.h"
48 #include "send-stream.h"
49 #include "send-utils.h"
51 static int g_verbose = 0;
62 char *dest_dir_path; /* relative to root_path */
63 char *full_subvol_path;
67 struct subvol_info cur_subvol;
69 struct subvol_uuid_search sus;
74 * Buffer to store capabilities from security.capabilities xattr,
75 * usually 20 bytes, but make same room for potentially larger
76 * encodings. Must be set only once per file, denoted by length > 0.
78 char cached_capabilities[64];
79 int cached_capabilities_len;
82 static int finish_subvol(struct btrfs_receive *r)
86 struct btrfs_ioctl_received_subvol_args rs_args;
87 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
90 if (r->cur_subvol.path == NULL)
93 subvol_fd = openat(r->mnt_fd, r->cur_subvol.path,
94 O_RDONLY | O_NOATIME);
97 fprintf(stderr, "ERROR: open %s failed. %s\n",
98 r->cur_subvol.path, strerror(-ret));
102 memset(&rs_args, 0, sizeof(rs_args));
103 memcpy(rs_args.uuid, r->cur_subvol.received_uuid, BTRFS_UUID_SIZE);
104 rs_args.stransid = r->cur_subvol.stransid;
106 if (g_verbose >= 1) {
107 uuid_unparse((u8*)rs_args.uuid, uuid_str);
108 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
109 "stransid=%llu\n", uuid_str, rs_args.stransid);
112 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
115 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
119 r->cur_subvol.rtransid = rs_args.rtransid;
121 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
124 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
129 flags |= BTRFS_SUBVOL_RDONLY;
131 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
134 fprintf(stderr, "ERROR: failed to make subvolume read only. "
135 "%s\n", strerror(-ret));
142 if (r->cur_subvol.path) {
143 free(r->cur_subvol.path);
144 r->cur_subvol.path = NULL;
151 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
155 struct btrfs_receive *r = user;
156 struct btrfs_ioctl_vol_args args_v1;
157 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
159 ret = finish_subvol(r);
163 BUG_ON(r->cur_subvol.path);
165 if (strlen(r->dest_dir_path) == 0)
166 r->cur_subvol.path = strdup(path);
168 r->cur_subvol.path = path_cat(r->dest_dir_path, path);
169 free(r->full_subvol_path);
170 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
172 fprintf(stderr, "At subvol %s\n", path);
174 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
175 r->cur_subvol.stransid = ctransid;
178 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
179 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
181 r->cur_subvol.stransid);
184 memset(&args_v1, 0, sizeof(args_v1));
185 strncpy_null(args_v1.name, path);
186 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
189 fprintf(stderr, "ERROR: creating subvolume %s failed. "
190 "%s\n", path, strerror(-ret));
198 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
199 const u8 *parent_uuid, u64 parent_ctransid,
203 struct btrfs_receive *r = user;
204 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
205 struct btrfs_ioctl_vol_args_v2 args_v2;
206 struct subvol_info *parent_subvol = NULL;
208 ret = finish_subvol(r);
212 BUG_ON(r->cur_subvol.path);
214 if (strlen(r->dest_dir_path) == 0)
215 r->cur_subvol.path = strdup(path);
217 r->cur_subvol.path = path_cat(r->dest_dir_path, path);
218 free(r->full_subvol_path);
219 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
221 fprintf(stdout, "At snapshot %s\n", path);
223 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
224 r->cur_subvol.stransid = ctransid;
227 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
228 fprintf(stderr, "receiving snapshot %s uuid=%s, "
229 "ctransid=%llu ", path, uuid_str,
230 r->cur_subvol.stransid);
231 uuid_unparse(parent_uuid, uuid_str);
232 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
233 uuid_str, parent_ctransid);
236 memset(&args_v2, 0, sizeof(args_v2));
237 strncpy_null(args_v2.name, path);
239 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
240 parent_ctransid, NULL, subvol_search_by_received_uuid);
241 if (!parent_subvol) {
242 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
243 parent_ctransid, NULL, subvol_search_by_uuid);
245 if (!parent_subvol) {
247 fprintf(stderr, "ERROR: could not find parent subvolume\n");
252 * The path is resolved from the root subvol, but we could be in some
253 * subvolume under the root subvolume, so try and adjust the path to be
254 * relative to our root path.
256 if (r->full_root_path) {
260 root_len = strlen(r->full_root_path);
261 sub_len = strlen(parent_subvol->path);
263 /* First make sure the parent subvol is actually in our path */
264 if (sub_len < root_len ||
265 strstr(parent_subvol->path, r->full_root_path) == NULL) {
266 fprintf(stderr, "ERROR: parent subvol is not reachable"
267 " from inside the root subvol.\n");
272 if (sub_len == root_len) {
273 parent_subvol->path[0] = '/';
274 parent_subvol->path[1] = '\0';
277 * root path is foo/bar
278 * subvol path is foo/bar/baz
280 * we need to have baz be the path, so we need to move
281 * the bit after foo/bar/, so path + root_len + 1, and
282 * move the part we care about, so sub_len - root_len -
285 memmove(parent_subvol->path,
286 parent_subvol->path + root_len + 1,
287 sub_len - root_len - 1);
288 parent_subvol->path[sub_len - root_len - 1] = '\0';
291 /*if (rs_args.ctransid > rs_args.rtransid) {
294 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
297 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
301 if (strlen(parent_subvol->path) == 0)
302 args_v2.fd = dup(r->mnt_fd);
304 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
305 O_RDONLY | O_NOATIME);
306 if (args_v2.fd < 0) {
309 fprintf(stderr, "ERROR: open %s failed. %s\n",
310 parent_subvol->path, strerror(-ret));
313 "It seems that you have changed your default "
314 "subvolume or you specify other subvolume to\n"
315 "mount btrfs, try to remount this btrfs filesystem "
316 "with fs tree, and run btrfs receive again!\n");
320 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
324 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
325 "failed. %s\n", parent_subvol->path,
326 path, strerror(-ret));
332 free(parent_subvol->path);
338 static int process_mkfile(const char *path, void *user)
341 struct btrfs_receive *r = user;
342 char *full_path = path_cat(r->full_subvol_path, path);
345 fprintf(stderr, "mkfile %s\n", path);
347 ret = creat(full_path, 0600);
350 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
362 static int process_mkdir(const char *path, void *user)
365 struct btrfs_receive *r = user;
366 char *full_path = path_cat(r->full_subvol_path, path);
369 fprintf(stderr, "mkdir %s\n", path);
371 ret = mkdir(full_path, 0700);
374 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
382 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
385 struct btrfs_receive *r = user;
386 char *full_path = path_cat(r->full_subvol_path, path);
389 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
392 ret = mknod(full_path, mode & S_IFMT, dev);
395 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
403 static int process_mkfifo(const char *path, void *user)
406 struct btrfs_receive *r = user;
407 char *full_path = path_cat(r->full_subvol_path, path);
410 fprintf(stderr, "mkfifo %s\n", path);
412 ret = mkfifo(full_path, 0600);
415 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
423 static int process_mksock(const char *path, void *user)
426 struct btrfs_receive *r = user;
427 char *full_path = path_cat(r->full_subvol_path, path);
430 fprintf(stderr, "mksock %s\n", path);
432 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
435 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
443 static int process_symlink(const char *path, const char *lnk, void *user)
446 struct btrfs_receive *r = user;
447 char *full_path = path_cat(r->full_subvol_path, path);
450 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
452 ret = symlink(lnk, full_path);
455 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
456 lnk, strerror(-ret));
463 static int process_rename(const char *from, const char *to, void *user)
466 struct btrfs_receive *r = user;
467 char *full_from = path_cat(r->full_subvol_path, from);
468 char *full_to = path_cat(r->full_subvol_path, to);
471 fprintf(stderr, "rename %s -> %s\n", from, to);
473 ret = rename(full_from, full_to);
476 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
485 static int process_link(const char *path, const char *lnk, void *user)
488 struct btrfs_receive *r = user;
489 char *full_path = path_cat(r->full_subvol_path, path);
490 char *full_link_path = path_cat(r->full_subvol_path, lnk);
493 fprintf(stderr, "link %s -> %s\n", path, lnk);
495 ret = link(full_link_path, full_path);
498 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
499 lnk, strerror(-ret));
503 free(full_link_path);
508 static int process_unlink(const char *path, void *user)
511 struct btrfs_receive *r = user;
512 char *full_path = path_cat(r->full_subvol_path, path);
515 fprintf(stderr, "unlink %s\n", path);
517 ret = unlink(full_path);
520 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
528 static int process_rmdir(const char *path, void *user)
531 struct btrfs_receive *r = user;
532 char *full_path = path_cat(r->full_subvol_path, path);
535 fprintf(stderr, "rmdir %s\n", path);
537 ret = rmdir(full_path);
540 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
549 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
553 if (r->write_fd != -1) {
554 if (strcmp(r->write_path, path) == 0)
560 r->write_fd = open(path, O_RDWR);
561 if (r->write_fd < 0) {
563 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
568 r->write_path = strdup(path);
574 static void close_inode_for_write(struct btrfs_receive *r)
576 if(r->write_fd == -1)
581 r->write_path[0] = 0;
584 static int process_write(const char *path, const void *data, u64 offset,
588 struct btrfs_receive *r = user;
589 char *full_path = path_cat(r->full_subvol_path, path);
593 ret = open_inode_for_write(r, full_path);
598 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
602 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
603 path, strerror(-ret));
614 static int process_clone(const char *path, u64 offset, u64 len,
615 const u8 *clone_uuid, u64 clone_ctransid,
616 const char *clone_path, u64 clone_offset,
620 struct btrfs_receive *r = user;
621 struct btrfs_ioctl_clone_range_args clone_args;
622 struct subvol_info *si = NULL;
623 char *full_path = path_cat(r->full_subvol_path, path);
624 char *subvol_path = NULL;
625 char *full_clone_path = NULL;
628 ret = open_inode_for_write(r, full_path);
632 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
633 subvol_search_by_received_uuid);
635 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
636 BTRFS_UUID_SIZE) == 0) {
637 /* TODO check generation of extent */
638 subvol_path = strdup(r->cur_subvol.path);
641 fprintf(stderr, "ERROR: did not find source subvol.\n");
645 /*if (rs_args.ctransid > rs_args.rtransid) {
648 fprintf(stderr, "ERROR: subvolume %s was "
649 "modified after it was "
651 r->subvol_parent_name);
654 fprintf(stderr, "WARNING: subvolume %s was "
655 "modified after it was "
657 r->subvol_parent_name);
660 subvol_path = strdup(si->path);
663 full_clone_path = path_cat(subvol_path, clone_path);
665 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
668 fprintf(stderr, "ERROR: failed to open %s. %s\n",
669 full_clone_path, strerror(-ret));
673 clone_args.src_fd = clone_fd;
674 clone_args.src_offset = clone_offset;
675 clone_args.src_length = len;
676 clone_args.dest_offset = offset;
677 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
680 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
681 path, strerror(-ret));
691 free(full_clone_path);
699 static int process_set_xattr(const char *path, const char *name,
700 const void *data, int len, void *user)
703 struct btrfs_receive *r = user;
704 char *full_path = path_cat(r->full_subvol_path, path);
706 if (strcmp("security.capability", name) == 0) {
708 fprintf(stderr, "set_xattr: cache capabilities\n");
709 if (r->cached_capabilities_len)
711 "WARNING: capabilities set multiple times per file: %s\n",
713 if (len > sizeof(r->cached_capabilities)) {
715 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
720 r->cached_capabilities_len = len;
721 memcpy(r->cached_capabilities, data, len);
724 if (g_verbose >= 2) {
725 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
726 "data=%.*s\n", path, name, len,
730 ret = lsetxattr(full_path, name, data, len, 0);
733 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
734 path, name, len, (char*)data, strerror(-ret));
743 static int process_remove_xattr(const char *path, const char *name, void *user)
746 struct btrfs_receive *r = user;
747 char *full_path = path_cat(r->full_subvol_path, path);
749 if (g_verbose >= 2) {
750 fprintf(stderr, "remove_xattr %s - name=%s\n",
754 ret = lremovexattr(full_path, name);
757 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
758 path, name, strerror(-ret));
767 static int process_truncate(const char *path, u64 size, void *user)
770 struct btrfs_receive *r = user;
771 char *full_path = path_cat(r->full_subvol_path, path);
774 fprintf(stderr, "truncate %s size=%llu\n", path, size);
776 ret = truncate(full_path, size);
779 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
780 path, strerror(-ret));
789 static int process_chmod(const char *path, u64 mode, void *user)
792 struct btrfs_receive *r = user;
793 char *full_path = path_cat(r->full_subvol_path, path);
796 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
798 ret = chmod(full_path, mode);
801 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
802 path, strerror(-ret));
811 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
814 struct btrfs_receive *r = user;
815 char *full_path = path_cat(r->full_subvol_path, path);
818 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
821 ret = lchown(full_path, uid, gid);
824 fprintf(stderr, "ERROR: chown %s failed. %s\n",
825 path, strerror(-ret));
829 if (r->cached_capabilities_len) {
831 fprintf(stderr, "chown: restore capabilities\n");
832 ret = lsetxattr(full_path, "security.capability",
833 r->cached_capabilities,
834 r->cached_capabilities_len, 0);
835 memset(r->cached_capabilities, 0,
836 sizeof(r->cached_capabilities));
837 r->cached_capabilities_len = 0;
840 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
841 path, strerror(-ret));
851 static int process_utimes(const char *path, struct timespec *at,
852 struct timespec *mt, struct timespec *ct,
856 struct btrfs_receive *r = user;
857 char *full_path = path_cat(r->full_subvol_path, path);
858 struct timespec tv[2];
861 fprintf(stderr, "utimes %s\n", path);
865 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
868 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
869 path, strerror(-ret));
878 static int process_update_extent(const char *path, u64 offset, u64 len,
882 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
883 path, (unsigned long long)offset,
884 (unsigned long long)len);
887 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
893 static struct btrfs_send_ops send_ops = {
894 .subvol = process_subvol,
895 .snapshot = process_snapshot,
896 .mkfile = process_mkfile,
897 .mkdir = process_mkdir,
898 .mknod = process_mknod,
899 .mkfifo = process_mkfifo,
900 .mksock = process_mksock,
901 .symlink = process_symlink,
902 .rename = process_rename,
903 .link = process_link,
904 .unlink = process_unlink,
905 .rmdir = process_rmdir,
906 .write = process_write,
907 .clone = process_clone,
908 .set_xattr = process_set_xattr,
909 .remove_xattr = process_remove_xattr,
910 .truncate = process_truncate,
911 .chmod = process_chmod,
912 .chown = process_chown,
913 .utimes = process_utimes,
914 .update_extent = process_update_extent,
917 static int do_receive(struct btrfs_receive *r, const char *tomnt,
918 char *realmnt, int r_fd, u64 max_errors)
922 char *dest_dir_full_path;
923 char *root_subvol_path;
926 dest_dir_full_path = realpath(tomnt, NULL);
927 if (!dest_dir_full_path) {
929 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
933 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
934 if (r->dest_dir_fd < 0) {
937 "ERROR: failed to open destination directory %s. %s\n",
938 dest_dir_full_path, strerror(-ret));
943 r->root_path = realmnt;
945 ret = find_mount_root(dest_dir_full_path, &r->root_path);
948 "ERROR: failed to determine mount point for %s: %s\n",
949 dest_dir_full_path, strerror(-ret));
955 "ERROR: %s doesn't belong to btrfs mount point\n",
961 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
964 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
970 * If we use -m or a default subvol we want to resolve the path to the
971 * subvolume we're sitting in so that we can adjust the paths of any
972 * subvols we want to receive in.
974 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
976 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
981 root_subvol_path = malloc(PATH_MAX);
982 if (!root_subvol_path) {
984 fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
989 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
990 PATH_MAX, subvol_id);
992 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
997 * Ok we're inside of a subvol off of the root subvol, we need to
998 * actually set full_root_path.
1000 if (strlen(root_subvol_path))
1001 r->full_root_path = root_subvol_path;
1003 free(root_subvol_path);
1005 if (r->dest_dir_chroot) {
1006 if (chroot(dest_dir_full_path)) {
1009 "ERROR: failed to chroot to %s, %s\n",
1017 "ERROR: failed to chdir to /, %s\n",
1021 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1022 r->root_path = strdup("/");
1023 r->dest_dir_path = r->root_path;
1026 * find_mount_root returns a root_path that is a subpath of
1027 * dest_dir_full_path. Now get the other part of root_path,
1028 * which is the destination dir relative to root_path.
1030 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1031 while (r->dest_dir_path[0] == '/')
1035 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1040 if (r->cached_capabilities_len) {
1042 fprintf(stderr, "clear cached capabilities\n");
1043 memset(r->cached_capabilities, 0,
1044 sizeof(r->cached_capabilities));
1045 r->cached_capabilities_len = 0;
1048 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1056 close_inode_for_write(r);
1057 ret = finish_subvol(r);
1064 if (r->write_fd != -1) {
1069 r->root_path = NULL;
1070 free(r->write_path);
1071 r->write_path = NULL;
1072 free(r->full_subvol_path);
1073 r->full_subvol_path = NULL;
1074 r->dest_dir_path = NULL;
1075 free(dest_dir_full_path);
1076 if (r->cur_subvol.path) {
1077 free(r->cur_subvol.path);
1078 r->cur_subvol.path = NULL;
1080 subvol_uuid_search_finit(&r->sus);
1081 if (r->mnt_fd != -1) {
1085 if (r->dest_dir_fd != -1) {
1086 close(r->dest_dir_fd);
1087 r->dest_dir_fd = -1;
1089 if (r->full_root_path) {
1090 free(r->full_root_path);
1091 r->full_root_path = NULL;
1096 int cmd_receive(int argc, char **argv)
1099 char *fromfile = NULL;
1100 char *realmnt = NULL;
1101 struct btrfs_receive r;
1102 int receive_fd = fileno(stdin);
1106 memset(&r, 0, sizeof(r));
1110 r.dest_dir_chroot = 0;
1114 static const struct option long_opts[] = {
1115 { "max-errors", required_argument, NULL, 'E' },
1116 { "chroot", no_argument, NULL, 'C' },
1117 { NULL, 0, NULL, 0 }
1120 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1132 r.honor_end_cmd = 1;
1135 r.dest_dir_chroot = 1;
1138 max_errors = arg_strtou64(optarg);
1142 realmnt = strdup(optarg);
1144 fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
1150 fprintf(stderr, "ERROR: receive args invalid.\n");
1155 if (check_argc_exact(argc - optind, 1))
1156 usage(cmd_receive_usage);
1158 tomnt = argv[optind];
1161 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1162 if (receive_fd < 0) {
1163 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1168 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1176 const char * const cmd_receive_usage[] = {
1177 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1178 "Receive subvolumes from stdin.",
1179 "Receives one or more subvolumes that were previously",
1180 "sent with btrfs send. The received subvolumes are stored",
1182 "btrfs receive will fail in case a receiving subvolume",
1183 "already exists. It will also fail in case a previously",
1184 "received subvolume was changed after it was received.",
1185 "After receiving a subvolume, it is immediately set to",
1187 "-v Enable verbose debug output. Each",
1188 " occurrence of this option increases the",
1189 " verbose level more.",
1190 "-f <infile> By default, btrfs receive uses stdin",
1191 " to receive the subvolumes. Use this",
1192 " option to specify a file to use instead.",
1193 "-e Terminate after receiving an <end cmd>",
1194 " in the data stream. Without this option,",
1195 " the receiver terminates only if an error",
1196 " is recognized or on EOF.",
1197 "-C|--chroot confine the process to <mount> using chroot",
1198 "--max-errors <N> Terminate as soon as N errors happened while",
1199 " processing commands from the send stream.",
1200 " Default value is 1. A value of 0 means no limit.",
1201 "-m <mountpoint> The root mount point of the destination fs.",
1202 " If you do not have /proc use this to tell us where ",
1203 " this file system is mounted.",