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));
879 static int process_update_extent(const char *path, u64 offset, u64 len,
883 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
884 path, (unsigned long long)offset,
885 (unsigned long long)len);
888 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
894 static struct btrfs_send_ops send_ops = {
895 .subvol = process_subvol,
896 .snapshot = process_snapshot,
897 .mkfile = process_mkfile,
898 .mkdir = process_mkdir,
899 .mknod = process_mknod,
900 .mkfifo = process_mkfifo,
901 .mksock = process_mksock,
902 .symlink = process_symlink,
903 .rename = process_rename,
904 .link = process_link,
905 .unlink = process_unlink,
906 .rmdir = process_rmdir,
907 .write = process_write,
908 .clone = process_clone,
909 .set_xattr = process_set_xattr,
910 .remove_xattr = process_remove_xattr,
911 .truncate = process_truncate,
912 .chmod = process_chmod,
913 .chown = process_chown,
914 .utimes = process_utimes,
915 .update_extent = process_update_extent,
918 static int do_receive(struct btrfs_receive *r, const char *tomnt,
919 char *realmnt, int r_fd, u64 max_errors)
923 char *dest_dir_full_path;
924 char *root_subvol_path;
927 dest_dir_full_path = realpath(tomnt, NULL);
928 if (!dest_dir_full_path) {
930 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
934 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
935 if (r->dest_dir_fd < 0) {
938 "ERROR: failed to open destination directory %s. %s\n",
939 dest_dir_full_path, strerror(-ret));
944 r->root_path = realmnt;
946 ret = find_mount_root(dest_dir_full_path, &r->root_path);
949 "ERROR: failed to determine mount point for %s: %s\n",
950 dest_dir_full_path, strerror(-ret));
956 "ERROR: %s doesn't belong to btrfs mount point\n",
962 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
965 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
971 * If we use -m or a default subvol we want to resolve the path to the
972 * subvolume we're sitting in so that we can adjust the paths of any
973 * subvols we want to receive in.
975 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
977 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
982 root_subvol_path = malloc(BTRFS_PATH_NAME_MAX);
983 if (!root_subvol_path) {
985 fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
990 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
991 BTRFS_PATH_NAME_MAX, subvol_id);
993 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
998 * Ok we're inside of a subvol off of the root subvol, we need to
999 * actually set full_root_path.
1001 if (strlen(root_subvol_path))
1002 r->full_root_path = root_subvol_path;
1004 free(root_subvol_path);
1006 if (r->dest_dir_chroot) {
1007 if (chroot(dest_dir_full_path)) {
1010 "ERROR: failed to chroot to %s, %s\n",
1018 "ERROR: failed to chdir to /, %s\n",
1022 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1023 r->root_path = strdup("/");
1024 r->dest_dir_path = r->root_path;
1027 * find_mount_root returns a root_path that is a subpath of
1028 * dest_dir_full_path. Now get the other part of root_path,
1029 * which is the destination dir relative to root_path.
1031 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1032 while (r->dest_dir_path[0] == '/')
1036 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1041 if (r->cached_capabilities_len) {
1043 fprintf(stderr, "clear cached capabilities\n");
1044 memset(r->cached_capabilities, 0,
1045 sizeof(r->cached_capabilities));
1046 r->cached_capabilities_len = 0;
1049 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1057 close_inode_for_write(r);
1058 ret = finish_subvol(r);
1065 if (r->write_fd != -1) {
1070 r->root_path = NULL;
1071 free(r->write_path);
1072 r->write_path = NULL;
1073 free(r->full_subvol_path);
1074 r->full_subvol_path = NULL;
1075 r->dest_dir_path = NULL;
1076 free(dest_dir_full_path);
1077 if (r->cur_subvol) {
1078 free(r->cur_subvol->path);
1079 free(r->cur_subvol);
1080 r->cur_subvol = NULL;
1082 subvol_uuid_search_finit(&r->sus);
1083 if (r->mnt_fd != -1) {
1087 if (r->dest_dir_fd != -1) {
1088 close(r->dest_dir_fd);
1089 r->dest_dir_fd = -1;
1091 if (r->full_root_path) {
1092 free(r->full_root_path);
1093 r->full_root_path = NULL;
1098 int cmd_receive(int argc, char **argv)
1101 char *fromfile = NULL;
1102 char *realmnt = NULL;
1103 struct btrfs_receive r;
1104 int receive_fd = fileno(stdin);
1108 memset(&r, 0, sizeof(r));
1112 r.dest_dir_chroot = 0;
1116 static const struct option long_opts[] = {
1117 { "max-errors", required_argument, NULL, 'E' },
1118 { "chroot", no_argument, NULL, 'C' },
1119 { NULL, 0, NULL, 0 }
1122 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1134 r.honor_end_cmd = 1;
1137 r.dest_dir_chroot = 1;
1140 max_errors = arg_strtou64(optarg);
1144 realmnt = strdup(optarg);
1146 fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
1152 fprintf(stderr, "ERROR: receive args invalid.\n");
1157 if (check_argc_exact(argc - optind, 1))
1158 usage(cmd_receive_usage);
1160 tomnt = argv[optind];
1163 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1164 if (receive_fd < 0) {
1165 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1170 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1178 const char * const cmd_receive_usage[] = {
1179 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1180 "Receive subvolumes from stdin.",
1181 "Receives one or more subvolumes that were previously",
1182 "sent with btrfs send. The received subvolumes are stored",
1184 "btrfs receive will fail in case a receiving subvolume",
1185 "already exists. It will also fail in case a previously",
1186 "received subvolume was changed after it was received.",
1187 "After receiving a subvolume, it is immediately set to",
1189 "-v Enable verbose debug output. Each",
1190 " occurrence of this option increases the",
1191 " verbose level more.",
1192 "-f <infile> By default, btrfs receive uses stdin",
1193 " to receive the subvolumes. Use this",
1194 " option to specify a file to use instead.",
1195 "-e Terminate after receiving an <end cmd>",
1196 " in the data stream. Without this option,",
1197 " the receiver terminates only if an error",
1198 " is recognized or on EOF.",
1199 "-C|--chroot confine the process to <mount> using chroot",
1200 "--max-errors <N> Terminate as soon as N errors happened while",
1201 " processing commands from the send stream.",
1202 " Default value is 1. A value of 0 means no limit.",
1203 "-m <mountpoint> The root mount point of the destination fs.",
1204 " If you do not have /proc use this to tell us where ",
1205 " this file system is mounted.",