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 == 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));
143 free(r->cur_subvol->path);
145 r->cur_subvol = NULL;
152 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
156 struct btrfs_receive *r = user;
157 struct btrfs_ioctl_vol_args args_v1;
158 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
160 ret = finish_subvol(r);
164 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
166 if (strlen(r->dest_dir_path) == 0)
167 r->cur_subvol->path = strdup(path);
169 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
170 free(r->full_subvol_path);
171 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
173 fprintf(stderr, "At subvol %s\n", path);
175 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
176 r->cur_subvol->stransid = ctransid;
179 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
180 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
182 r->cur_subvol->stransid);
185 memset(&args_v1, 0, sizeof(args_v1));
186 strncpy_null(args_v1.name, path);
187 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
190 fprintf(stderr, "ERROR: creating subvolume %s failed. "
191 "%s\n", path, strerror(-ret));
199 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
200 const u8 *parent_uuid, u64 parent_ctransid,
204 struct btrfs_receive *r = user;
205 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
206 struct btrfs_ioctl_vol_args_v2 args_v2;
207 struct subvol_info *parent_subvol = NULL;
209 ret = finish_subvol(r);
213 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
215 if (strlen(r->dest_dir_path) == 0)
216 r->cur_subvol->path = strdup(path);
218 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
219 free(r->full_subvol_path);
220 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
222 fprintf(stdout, "At snapshot %s\n", path);
224 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
225 r->cur_subvol->stransid = ctransid;
228 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
229 fprintf(stderr, "receiving snapshot %s uuid=%s, "
230 "ctransid=%llu ", path, uuid_str,
231 r->cur_subvol->stransid);
232 uuid_unparse(parent_uuid, uuid_str);
233 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
234 uuid_str, parent_ctransid);
237 memset(&args_v2, 0, sizeof(args_v2));
238 strncpy_null(args_v2.name, path);
240 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
241 parent_ctransid, NULL, subvol_search_by_received_uuid);
242 if (!parent_subvol) {
243 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
244 parent_ctransid, NULL, subvol_search_by_uuid);
246 if (!parent_subvol) {
248 fprintf(stderr, "ERROR: could not find parent subvolume\n");
253 * The path is resolved from the root subvol, but we could be in some
254 * subvolume under the root subvolume, so try and adjust the path to be
255 * relative to our root path.
257 if (r->full_root_path) {
261 root_len = strlen(r->full_root_path);
262 sub_len = strlen(parent_subvol->path);
264 /* First make sure the parent subvol is actually in our path */
265 if (sub_len < root_len ||
266 strstr(parent_subvol->path, r->full_root_path) == NULL) {
267 fprintf(stderr, "ERROR: parent subvol is not reachable"
268 " from inside the root subvol.\n");
273 if (sub_len == root_len) {
274 parent_subvol->path[0] = '/';
275 parent_subvol->path[1] = '\0';
278 * root path is foo/bar
279 * subvol path is foo/bar/baz
281 * we need to have baz be the path, so we need to move
282 * the bit after foo/bar/, so path + root_len + 1, and
283 * move the part we care about, so sub_len - root_len -
286 memmove(parent_subvol->path,
287 parent_subvol->path + root_len + 1,
288 sub_len - root_len - 1);
289 parent_subvol->path[sub_len - root_len - 1] = '\0';
292 /*if (rs_args.ctransid > rs_args.rtransid) {
295 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
298 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
302 if (strlen(parent_subvol->path) == 0)
303 args_v2.fd = dup(r->mnt_fd);
305 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
306 O_RDONLY | O_NOATIME);
307 if (args_v2.fd < 0) {
310 fprintf(stderr, "ERROR: open %s failed. %s\n",
311 parent_subvol->path, strerror(-ret));
314 "It seems that you have changed your default "
315 "subvolume or you specify other subvolume to\n"
316 "mount btrfs, try to remount this btrfs filesystem "
317 "with fs tree, and run btrfs receive again!\n");
321 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
325 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
326 "failed. %s\n", parent_subvol->path,
327 path, strerror(-ret));
333 free(parent_subvol->path);
339 static int process_mkfile(const char *path, void *user)
342 struct btrfs_receive *r = user;
343 char *full_path = path_cat(r->full_subvol_path, path);
346 fprintf(stderr, "mkfile %s\n", path);
348 ret = creat(full_path, 0600);
351 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
363 static int process_mkdir(const char *path, void *user)
366 struct btrfs_receive *r = user;
367 char *full_path = path_cat(r->full_subvol_path, path);
370 fprintf(stderr, "mkdir %s\n", path);
372 ret = mkdir(full_path, 0700);
375 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
383 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
386 struct btrfs_receive *r = user;
387 char *full_path = path_cat(r->full_subvol_path, path);
390 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
393 ret = mknod(full_path, mode & S_IFMT, dev);
396 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
404 static int process_mkfifo(const char *path, void *user)
407 struct btrfs_receive *r = user;
408 char *full_path = path_cat(r->full_subvol_path, path);
411 fprintf(stderr, "mkfifo %s\n", path);
413 ret = mkfifo(full_path, 0600);
416 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
424 static int process_mksock(const char *path, void *user)
427 struct btrfs_receive *r = user;
428 char *full_path = path_cat(r->full_subvol_path, path);
431 fprintf(stderr, "mksock %s\n", path);
433 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
436 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
444 static int process_symlink(const char *path, const char *lnk, void *user)
447 struct btrfs_receive *r = user;
448 char *full_path = path_cat(r->full_subvol_path, path);
451 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
453 ret = symlink(lnk, full_path);
456 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
457 lnk, strerror(-ret));
464 static int process_rename(const char *from, const char *to, void *user)
467 struct btrfs_receive *r = user;
468 char *full_from = path_cat(r->full_subvol_path, from);
469 char *full_to = path_cat(r->full_subvol_path, to);
472 fprintf(stderr, "rename %s -> %s\n", from, to);
474 ret = rename(full_from, full_to);
477 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
486 static int process_link(const char *path, const char *lnk, void *user)
489 struct btrfs_receive *r = user;
490 char *full_path = path_cat(r->full_subvol_path, path);
491 char *full_link_path = path_cat(r->full_subvol_path, lnk);
494 fprintf(stderr, "link %s -> %s\n", path, lnk);
496 ret = link(full_link_path, full_path);
499 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
500 lnk, strerror(-ret));
504 free(full_link_path);
509 static int process_unlink(const char *path, void *user)
512 struct btrfs_receive *r = user;
513 char *full_path = path_cat(r->full_subvol_path, path);
516 fprintf(stderr, "unlink %s\n", path);
518 ret = unlink(full_path);
521 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
529 static int process_rmdir(const char *path, void *user)
532 struct btrfs_receive *r = user;
533 char *full_path = path_cat(r->full_subvol_path, path);
536 fprintf(stderr, "rmdir %s\n", path);
538 ret = rmdir(full_path);
541 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
550 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
554 if (r->write_fd != -1) {
555 if (strcmp(r->write_path, path) == 0)
561 r->write_fd = open(path, O_RDWR);
562 if (r->write_fd < 0) {
564 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
569 r->write_path = strdup(path);
575 static void close_inode_for_write(struct btrfs_receive *r)
577 if(r->write_fd == -1)
582 r->write_path[0] = 0;
585 static int process_write(const char *path, const void *data, u64 offset,
589 struct btrfs_receive *r = user;
590 char *full_path = path_cat(r->full_subvol_path, path);
594 ret = open_inode_for_write(r, full_path);
599 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
603 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
604 path, strerror(-ret));
615 static int process_clone(const char *path, u64 offset, u64 len,
616 const u8 *clone_uuid, u64 clone_ctransid,
617 const char *clone_path, u64 clone_offset,
621 struct btrfs_receive *r = user;
622 struct btrfs_ioctl_clone_range_args clone_args;
623 struct subvol_info *si = NULL;
624 char *full_path = path_cat(r->full_subvol_path, path);
625 char *subvol_path = NULL;
626 char *full_clone_path = NULL;
629 ret = open_inode_for_write(r, full_path);
633 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
634 subvol_search_by_received_uuid);
636 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
637 BTRFS_UUID_SIZE) == 0) {
638 /* TODO check generation of extent */
639 subvol_path = strdup(r->cur_subvol->path);
642 fprintf(stderr, "ERROR: did not find source subvol.\n");
646 /*if (rs_args.ctransid > rs_args.rtransid) {
649 fprintf(stderr, "ERROR: subvolume %s was "
650 "modified after it was "
652 r->subvol_parent_name);
655 fprintf(stderr, "WARNING: subvolume %s was "
656 "modified after it was "
658 r->subvol_parent_name);
661 subvol_path = strdup(si->path);
664 full_clone_path = path_cat(subvol_path, clone_path);
666 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
669 fprintf(stderr, "ERROR: failed to open %s. %s\n",
670 full_clone_path, strerror(-ret));
674 clone_args.src_fd = clone_fd;
675 clone_args.src_offset = clone_offset;
676 clone_args.src_length = len;
677 clone_args.dest_offset = offset;
678 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
681 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
682 path, strerror(-ret));
692 free(full_clone_path);
700 static int process_set_xattr(const char *path, const char *name,
701 const void *data, int len, void *user)
704 struct btrfs_receive *r = user;
705 char *full_path = path_cat(r->full_subvol_path, path);
707 if (strcmp("security.capability", name) == 0) {
709 fprintf(stderr, "set_xattr: cache capabilities\n");
710 if (r->cached_capabilities_len)
712 "WARNING: capabilities set multiple times per file: %s\n",
714 if (len > sizeof(r->cached_capabilities)) {
716 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
721 r->cached_capabilities_len = len;
722 memcpy(r->cached_capabilities, data, len);
725 if (g_verbose >= 2) {
726 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
727 "data=%.*s\n", path, name, len,
731 ret = lsetxattr(full_path, name, data, len, 0);
734 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
735 path, name, len, (char*)data, strerror(-ret));
744 static int process_remove_xattr(const char *path, const char *name, void *user)
747 struct btrfs_receive *r = user;
748 char *full_path = path_cat(r->full_subvol_path, path);
750 if (g_verbose >= 2) {
751 fprintf(stderr, "remove_xattr %s - name=%s\n",
755 ret = lremovexattr(full_path, name);
758 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
759 path, name, strerror(-ret));
768 static int process_truncate(const char *path, u64 size, void *user)
771 struct btrfs_receive *r = user;
772 char *full_path = path_cat(r->full_subvol_path, path);
775 fprintf(stderr, "truncate %s size=%llu\n", path, size);
777 ret = truncate(full_path, size);
780 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
781 path, strerror(-ret));
790 static int process_chmod(const char *path, u64 mode, void *user)
793 struct btrfs_receive *r = user;
794 char *full_path = path_cat(r->full_subvol_path, path);
797 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
799 ret = chmod(full_path, mode);
802 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
803 path, strerror(-ret));
812 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
815 struct btrfs_receive *r = user;
816 char *full_path = path_cat(r->full_subvol_path, path);
819 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
822 ret = lchown(full_path, uid, gid);
825 fprintf(stderr, "ERROR: chown %s failed. %s\n",
826 path, strerror(-ret));
830 if (r->cached_capabilities_len) {
832 fprintf(stderr, "chown: restore capabilities\n");
833 ret = lsetxattr(full_path, "security.capability",
834 r->cached_capabilities,
835 r->cached_capabilities_len, 0);
836 memset(r->cached_capabilities, 0,
837 sizeof(r->cached_capabilities));
838 r->cached_capabilities_len = 0;
841 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
842 path, strerror(-ret));
852 static int process_utimes(const char *path, struct timespec *at,
853 struct timespec *mt, struct timespec *ct,
857 struct btrfs_receive *r = user;
858 char *full_path = path_cat(r->full_subvol_path, path);
859 struct timespec tv[2];
862 fprintf(stderr, "utimes %s\n", path);
866 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
869 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
870 path, strerror(-ret));
880 static struct btrfs_send_ops send_ops = {
881 .subvol = process_subvol,
882 .snapshot = process_snapshot,
883 .mkfile = process_mkfile,
884 .mkdir = process_mkdir,
885 .mknod = process_mknod,
886 .mkfifo = process_mkfifo,
887 .mksock = process_mksock,
888 .symlink = process_symlink,
889 .rename = process_rename,
890 .link = process_link,
891 .unlink = process_unlink,
892 .rmdir = process_rmdir,
893 .write = process_write,
894 .clone = process_clone,
895 .set_xattr = process_set_xattr,
896 .remove_xattr = process_remove_xattr,
897 .truncate = process_truncate,
898 .chmod = process_chmod,
899 .chown = process_chown,
900 .utimes = process_utimes,
903 static int do_receive(struct btrfs_receive *r, const char *tomnt,
904 char *realmnt, int r_fd, u64 max_errors)
908 char *dest_dir_full_path;
909 char *root_subvol_path;
912 dest_dir_full_path = realpath(tomnt, NULL);
913 if (!dest_dir_full_path) {
915 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
919 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
920 if (r->dest_dir_fd < 0) {
923 "ERROR: failed to open destination directory %s. %s\n",
924 dest_dir_full_path, strerror(-ret));
929 r->root_path = realmnt;
931 ret = find_mount_root(dest_dir_full_path, &r->root_path);
934 "ERROR: failed to determine mount point for %s: %s\n",
935 dest_dir_full_path, strerror(-ret));
941 "ERROR: %s doesn't belong to btrfs mount point\n",
947 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
950 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
956 * If we use -m or a default subvol we want to resolve the path to the
957 * subvolume we're sitting in so that we can adjust the paths of any
958 * subvols we want to receive in.
960 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
962 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
967 root_subvol_path = malloc(BTRFS_PATH_NAME_MAX);
968 if (!root_subvol_path) {
970 fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
975 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
976 BTRFS_PATH_NAME_MAX, subvol_id);
978 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
983 * Ok we're inside of a subvol off of the root subvol, we need to
984 * actually set full_root_path.
986 if (strlen(root_subvol_path))
987 r->full_root_path = root_subvol_path;
989 free(root_subvol_path);
991 if (r->dest_dir_chroot) {
992 if (chroot(dest_dir_full_path)) {
995 "ERROR: failed to chroot to %s, %s\n",
1003 "ERROR: failed to chdir to /, %s\n",
1007 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1008 r->root_path = strdup("/");
1009 r->dest_dir_path = r->root_path;
1012 * find_mount_root returns a root_path that is a subpath of
1013 * dest_dir_full_path. Now get the other part of root_path,
1014 * which is the destination dir relative to root_path.
1016 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1017 while (r->dest_dir_path[0] == '/')
1021 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1026 if (r->cached_capabilities_len) {
1028 fprintf(stderr, "clear cached capabilities\n");
1029 memset(r->cached_capabilities, 0,
1030 sizeof(r->cached_capabilities));
1031 r->cached_capabilities_len = 0;
1034 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1042 close_inode_for_write(r);
1043 ret = finish_subvol(r);
1050 if (r->write_fd != -1) {
1055 r->root_path = NULL;
1056 free(r->write_path);
1057 r->write_path = NULL;
1058 free(r->full_subvol_path);
1059 r->full_subvol_path = NULL;
1060 r->dest_dir_path = NULL;
1061 free(dest_dir_full_path);
1062 if (r->cur_subvol) {
1063 free(r->cur_subvol->path);
1064 free(r->cur_subvol);
1065 r->cur_subvol = NULL;
1067 subvol_uuid_search_finit(&r->sus);
1068 if (r->mnt_fd != -1) {
1072 if (r->dest_dir_fd != -1) {
1073 close(r->dest_dir_fd);
1074 r->dest_dir_fd = -1;
1076 if (r->full_root_path) {
1077 free(r->full_root_path);
1078 r->full_root_path = NULL;
1083 int cmd_receive(int argc, char **argv)
1086 char *fromfile = NULL;
1087 char *realmnt = NULL;
1088 struct btrfs_receive r;
1089 int receive_fd = fileno(stdin);
1093 memset(&r, 0, sizeof(r));
1097 r.dest_dir_chroot = 0;
1101 static const struct option long_opts[] = {
1102 { "max-errors", required_argument, NULL, 'E' },
1103 { "chroot", no_argument, NULL, 'C' },
1104 { NULL, 0, NULL, 0 }
1107 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1119 r.honor_end_cmd = 1;
1122 r.dest_dir_chroot = 1;
1125 max_errors = arg_strtou64(optarg);
1129 realmnt = strdup(optarg);
1131 fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
1137 fprintf(stderr, "ERROR: receive args invalid.\n");
1142 if (check_argc_exact(argc - optind, 1))
1143 usage(cmd_receive_usage);
1145 tomnt = argv[optind];
1148 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1149 if (receive_fd < 0) {
1150 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1155 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1163 const char * const cmd_receive_usage[] = {
1164 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1165 "Receive subvolumes from stdin.",
1166 "Receives one or more subvolumes that were previously",
1167 "sent with btrfs send. The received subvolumes are stored",
1169 "btrfs receive will fail in case a receiving subvolume",
1170 "already exists. It will also fail in case a previously",
1171 "received subvolume was changed after it was received.",
1172 "After receiving a subvolume, it is immediately set to",
1174 "-v Enable verbose debug output. Each",
1175 " occurrence of this option increases the",
1176 " verbose level more.",
1177 "-f <infile> By default, btrfs receive uses stdin",
1178 " to receive the subvolumes. Use this",
1179 " option to specify a file to use instead.",
1180 "-e Terminate after receiving an <end cmd>",
1181 " in the data stream. Without this option,",
1182 " the receiver terminates only if an error",
1183 " is recognized or on EOF.",
1184 "-C|--chroot confine the process to <mount> using chroot",
1185 "--max-errors <N> Terminate as soon as N errors happened while",
1186 " processing commands from the send stream.",
1187 " Default value is 1. A value of 0 means no limit.",
1188 "-m <mountpoint> The root mount point of the destination fs.",
1189 " If you do not have /proc use this to tell us where ",
1190 " this file system is mounted.",