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;
59 char write_path[PATH_MAX];
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_MAX];
344 ret = path_cat_out(full_path, r->full_subvol_path, path);
346 fprintf(stderr, "ERROR: mkfile: path invalid: %s\n", path);
351 fprintf(stderr, "mkfile %s\n", path);
353 ret = creat(full_path, 0600);
356 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
367 static int process_mkdir(const char *path, void *user)
370 struct btrfs_receive *r = user;
371 char full_path[PATH_MAX];
373 ret = path_cat_out(full_path, r->full_subvol_path, path);
375 fprintf(stderr, "ERROR: mkdir: path invalid: %s\n", path);
380 fprintf(stderr, "mkdir %s\n", path);
382 ret = mkdir(full_path, 0700);
385 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
393 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
396 struct btrfs_receive *r = user;
397 char full_path[PATH_MAX];
399 ret = path_cat_out(full_path, r->full_subvol_path, path);
401 fprintf(stderr, "ERROR: mknod: path invalid: %s\n", path);
406 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
409 ret = mknod(full_path, mode & S_IFMT, dev);
412 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
420 static int process_mkfifo(const char *path, void *user)
423 struct btrfs_receive *r = user;
424 char full_path[PATH_MAX];
426 ret = path_cat_out(full_path, r->full_subvol_path, path);
428 fprintf(stderr, "ERROR: mkfifo: path invalid: %s\n", path);
433 fprintf(stderr, "mkfifo %s\n", path);
435 ret = mkfifo(full_path, 0600);
438 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
446 static int process_mksock(const char *path, void *user)
449 struct btrfs_receive *r = user;
450 char full_path[PATH_MAX];
452 ret = path_cat_out(full_path, r->full_subvol_path, path);
454 fprintf(stderr, "ERROR: mksock: path invalid: %s\n", path);
459 fprintf(stderr, "mksock %s\n", path);
461 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
464 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
472 static int process_symlink(const char *path, const char *lnk, void *user)
475 struct btrfs_receive *r = user;
476 char full_path[PATH_MAX];
478 ret = path_cat_out(full_path, r->full_subvol_path, path);
480 fprintf(stderr, "ERROR: symlink: path invalid: %s\n", path);
485 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
487 ret = symlink(lnk, full_path);
490 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
491 lnk, strerror(-ret));
498 static int process_rename(const char *from, const char *to, void *user)
501 struct btrfs_receive *r = user;
502 char full_from[PATH_MAX];
503 char full_to[PATH_MAX];
505 ret = path_cat_out(full_from, r->full_subvol_path, from);
507 fprintf(stderr, "ERROR: rename: source path invalid: %s\n",
512 ret = path_cat_out(full_to, r->full_subvol_path, to);
514 fprintf(stderr, "ERROR: rename: target path invalid: %s\n",
520 fprintf(stderr, "rename %s -> %s\n", from, to);
522 ret = rename(full_from, full_to);
525 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
533 static int process_link(const char *path, const char *lnk, void *user)
536 struct btrfs_receive *r = user;
537 char full_path[PATH_MAX];
538 char full_link_path[PATH_MAX];
540 ret = path_cat_out(full_path, r->full_subvol_path, path);
542 fprintf(stderr, "ERROR: link: source path invalid: %s\n",
547 ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
549 fprintf(stderr, "ERROR: link: target path invalid: %s\n",
555 fprintf(stderr, "link %s -> %s\n", path, lnk);
557 ret = link(full_link_path, full_path);
560 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
561 lnk, strerror(-ret));
569 static int process_unlink(const char *path, void *user)
572 struct btrfs_receive *r = user;
573 char full_path[PATH_MAX];
575 ret = path_cat_out(full_path, r->full_subvol_path, path);
577 fprintf(stderr, "ERROR: unlink: path invalid: %s\n", path);
582 fprintf(stderr, "unlink %s\n", path);
584 ret = unlink(full_path);
587 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
595 static int process_rmdir(const char *path, void *user)
598 struct btrfs_receive *r = user;
599 char full_path[PATH_MAX];
601 ret = path_cat_out(full_path, r->full_subvol_path, path);
603 fprintf(stderr, "ERROR: rmdir: path invalid: %s\n", path);
608 fprintf(stderr, "rmdir %s\n", path);
610 ret = rmdir(full_path);
613 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
621 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
625 if (r->write_fd != -1) {
626 if (strcmp(r->write_path, path) == 0)
632 r->write_fd = open(path, O_RDWR);
633 if (r->write_fd < 0) {
635 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
639 strncpy_null(r->write_path, path);
645 static void close_inode_for_write(struct btrfs_receive *r)
647 if(r->write_fd == -1)
652 r->write_path[0] = 0;
655 static int process_write(const char *path, const void *data, u64 offset,
659 struct btrfs_receive *r = user;
660 char full_path[PATH_MAX];
664 ret = path_cat_out(full_path, r->full_subvol_path, path);
666 fprintf(stderr, "ERROR: write: path invalid: %s\n", path);
670 ret = open_inode_for_write(r, full_path);
675 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
679 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
680 path, strerror(-ret));
690 static int process_clone(const char *path, u64 offset, u64 len,
691 const u8 *clone_uuid, u64 clone_ctransid,
692 const char *clone_path, u64 clone_offset,
696 struct btrfs_receive *r = user;
697 struct btrfs_ioctl_clone_range_args clone_args;
698 struct subvol_info *si = NULL;
699 char full_path[PATH_MAX];
700 char *subvol_path = NULL;
701 char full_clone_path[PATH_MAX];
704 ret = path_cat_out(full_path, r->full_subvol_path, path);
706 fprintf(stderr, "ERROR: clone: source path invalid: %s\n",
711 ret = open_inode_for_write(r, full_path);
715 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
716 subvol_search_by_received_uuid);
718 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
719 BTRFS_UUID_SIZE) == 0) {
720 /* TODO check generation of extent */
721 subvol_path = strdup(r->cur_subvol.path);
724 fprintf(stderr, "ERROR: did not find source subvol.\n");
728 /*if (rs_args.ctransid > rs_args.rtransid) {
731 fprintf(stderr, "ERROR: subvolume %s was "
732 "modified after it was "
734 r->subvol_parent_name);
737 fprintf(stderr, "WARNING: subvolume %s was "
738 "modified after it was "
740 r->subvol_parent_name);
743 subvol_path = strdup(si->path);
746 ret = path_cat_out(full_clone_path, subvol_path, clone_path);
748 fprintf(stderr, "ERROR: clone: target path invalid: %s\n",
753 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
756 fprintf(stderr, "ERROR: failed to open %s. %s\n",
757 full_clone_path, strerror(-ret));
761 clone_args.src_fd = clone_fd;
762 clone_args.src_offset = clone_offset;
763 clone_args.src_length = len;
764 clone_args.dest_offset = offset;
765 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
768 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
769 path, strerror(-ret));
785 static int process_set_xattr(const char *path, const char *name,
786 const void *data, int len, void *user)
789 struct btrfs_receive *r = user;
790 char full_path[PATH_MAX];
792 ret = path_cat_out(full_path, r->full_subvol_path, path);
794 fprintf(stderr, "ERROR: set_xattr: path invalid: %s\n", path);
798 if (strcmp("security.capability", name) == 0) {
800 fprintf(stderr, "set_xattr: cache capabilities\n");
801 if (r->cached_capabilities_len)
803 "WARNING: capabilities set multiple times per file: %s\n",
805 if (len > sizeof(r->cached_capabilities)) {
807 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
812 r->cached_capabilities_len = len;
813 memcpy(r->cached_capabilities, data, len);
816 if (g_verbose >= 2) {
817 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
818 "data=%.*s\n", path, name, len,
822 ret = lsetxattr(full_path, name, data, len, 0);
825 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
826 path, name, len, (char*)data, strerror(-ret));
834 static int process_remove_xattr(const char *path, const char *name, void *user)
837 struct btrfs_receive *r = user;
838 char full_path[PATH_MAX];
840 ret = path_cat_out(full_path, r->full_subvol_path, path);
842 fprintf(stderr, "ERROR: remove_xattr: path invalid: %s\n",
847 if (g_verbose >= 2) {
848 fprintf(stderr, "remove_xattr %s - name=%s\n",
852 ret = lremovexattr(full_path, name);
855 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
856 path, name, strerror(-ret));
864 static int process_truncate(const char *path, u64 size, void *user)
867 struct btrfs_receive *r = user;
868 char full_path[PATH_MAX];
870 ret = path_cat_out(full_path, r->full_subvol_path, path);
872 fprintf(stderr, "ERROR: truncate: path invalid: %s\n", path);
877 fprintf(stderr, "truncate %s size=%llu\n", path, size);
879 ret = truncate(full_path, size);
882 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
883 path, strerror(-ret));
891 static int process_chmod(const char *path, u64 mode, void *user)
894 struct btrfs_receive *r = user;
895 char full_path[PATH_MAX];
897 ret = path_cat_out(full_path, r->full_subvol_path, path);
899 fprintf(stderr, "ERROR: chmod: path invalid: %s\n", path);
904 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
906 ret = chmod(full_path, mode);
909 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
910 path, strerror(-ret));
918 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
921 struct btrfs_receive *r = user;
922 char full_path[PATH_MAX];
924 ret = path_cat_out(full_path, r->full_subvol_path, path);
926 fprintf(stderr, "ERROR: chown: path invalid: %s\n", path);
931 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
934 ret = lchown(full_path, uid, gid);
937 fprintf(stderr, "ERROR: chown %s failed. %s\n",
938 path, strerror(-ret));
942 if (r->cached_capabilities_len) {
944 fprintf(stderr, "chown: restore capabilities\n");
945 ret = lsetxattr(full_path, "security.capability",
946 r->cached_capabilities,
947 r->cached_capabilities_len, 0);
948 memset(r->cached_capabilities, 0,
949 sizeof(r->cached_capabilities));
950 r->cached_capabilities_len = 0;
953 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
954 path, strerror(-ret));
963 static int process_utimes(const char *path, struct timespec *at,
964 struct timespec *mt, struct timespec *ct,
968 struct btrfs_receive *r = user;
969 char full_path[PATH_MAX];
970 struct timespec tv[2];
972 ret = path_cat_out(full_path, r->full_subvol_path, path);
974 fprintf(stderr, "ERROR: utimes: path invalid: %s\n", path);
979 fprintf(stderr, "utimes %s\n", path);
983 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
986 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
987 path, strerror(-ret));
995 static int process_update_extent(const char *path, u64 offset, u64 len,
999 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1000 path, (unsigned long long)offset,
1001 (unsigned long long)len);
1004 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1010 static struct btrfs_send_ops send_ops = {
1011 .subvol = process_subvol,
1012 .snapshot = process_snapshot,
1013 .mkfile = process_mkfile,
1014 .mkdir = process_mkdir,
1015 .mknod = process_mknod,
1016 .mkfifo = process_mkfifo,
1017 .mksock = process_mksock,
1018 .symlink = process_symlink,
1019 .rename = process_rename,
1020 .link = process_link,
1021 .unlink = process_unlink,
1022 .rmdir = process_rmdir,
1023 .write = process_write,
1024 .clone = process_clone,
1025 .set_xattr = process_set_xattr,
1026 .remove_xattr = process_remove_xattr,
1027 .truncate = process_truncate,
1028 .chmod = process_chmod,
1029 .chown = process_chown,
1030 .utimes = process_utimes,
1031 .update_extent = process_update_extent,
1034 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1035 char *realmnt, int r_fd, u64 max_errors)
1039 char *dest_dir_full_path;
1040 char root_subvol_path[PATH_MAX];
1043 dest_dir_full_path = realpath(tomnt, NULL);
1044 if (!dest_dir_full_path) {
1046 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
1050 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1051 if (r->dest_dir_fd < 0) {
1054 "ERROR: failed to open destination directory %s. %s\n",
1055 dest_dir_full_path, strerror(-ret));
1060 r->root_path = realmnt;
1062 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1065 "ERROR: failed to determine mount point for %s: %s\n",
1066 dest_dir_full_path, strerror(-ret));
1072 "ERROR: %s doesn't belong to btrfs mount point\n",
1073 dest_dir_full_path);
1078 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1079 if (r->mnt_fd < 0) {
1081 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
1087 * If we use -m or a default subvol we want to resolve the path to the
1088 * subvolume we're sitting in so that we can adjust the paths of any
1089 * subvols we want to receive in.
1091 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1093 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
1098 root_subvol_path[0] = 0;
1099 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1100 PATH_MAX, subvol_id);
1102 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
1107 * Ok we're inside of a subvol off of the root subvol, we need to
1108 * actually set full_root_path.
1110 if (strlen(root_subvol_path))
1111 r->full_root_path = root_subvol_path;
1113 if (r->dest_dir_chroot) {
1114 if (chroot(dest_dir_full_path)) {
1117 "ERROR: failed to chroot to %s, %s\n",
1125 "ERROR: failed to chdir to /, %s\n",
1129 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1130 r->root_path = strdup("/");
1131 r->dest_dir_path = r->root_path;
1134 * find_mount_root returns a root_path that is a subpath of
1135 * dest_dir_full_path. Now get the other part of root_path,
1136 * which is the destination dir relative to root_path.
1138 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1139 while (r->dest_dir_path[0] == '/')
1143 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1148 if (r->cached_capabilities_len) {
1150 fprintf(stderr, "clear cached capabilities\n");
1151 memset(r->cached_capabilities, 0,
1152 sizeof(r->cached_capabilities));
1153 r->cached_capabilities_len = 0;
1156 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1164 close_inode_for_write(r);
1165 ret = finish_subvol(r);
1172 if (r->write_fd != -1) {
1177 r->root_path = NULL;
1178 free(r->full_subvol_path);
1179 r->full_subvol_path = NULL;
1180 r->dest_dir_path = NULL;
1181 free(dest_dir_full_path);
1182 if (r->cur_subvol.path) {
1183 free(r->cur_subvol.path);
1184 r->cur_subvol.path = NULL;
1186 subvol_uuid_search_finit(&r->sus);
1187 if (r->mnt_fd != -1) {
1191 if (r->dest_dir_fd != -1) {
1192 close(r->dest_dir_fd);
1193 r->dest_dir_fd = -1;
1199 int cmd_receive(int argc, char **argv)
1202 char fromfile[PATH_MAX];
1203 char realmnt[PATH_MAX];
1204 struct btrfs_receive r;
1205 int receive_fd = fileno(stdin);
1209 memset(&r, 0, sizeof(r));
1213 r.dest_dir_chroot = 0;
1219 static const struct option long_opts[] = {
1220 { "max-errors", required_argument, NULL, 'E' },
1221 { "chroot", no_argument, NULL, 'C' },
1222 { NULL, 0, NULL, 0 }
1225 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1234 if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1236 "ERROR: input file path too long (%zu)\n",
1243 r.honor_end_cmd = 1;
1246 r.dest_dir_chroot = 1;
1249 max_errors = arg_strtou64(optarg);
1252 if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1254 "ERROR: mount point path too long (%zu)\n",
1262 fprintf(stderr, "ERROR: receive args invalid.\n");
1267 if (check_argc_exact(argc - optind, 1))
1268 usage(cmd_receive_usage);
1270 tomnt = argv[optind];
1273 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1274 if (receive_fd < 0) {
1275 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1280 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1287 const char * const cmd_receive_usage[] = {
1288 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1289 "Receive subvolumes from stdin.",
1290 "Receives one or more subvolumes that were previously",
1291 "sent with btrfs send. The received subvolumes are stored",
1293 "btrfs receive will fail in case a receiving subvolume",
1294 "already exists. It will also fail in case a previously",
1295 "received subvolume was changed after it was received.",
1296 "After receiving a subvolume, it is immediately set to",
1298 "-v Enable verbose debug output. Each",
1299 " occurrence of this option increases the",
1300 " verbose level more.",
1301 "-f <infile> By default, btrfs receive uses stdin",
1302 " to receive the subvolumes. Use this",
1303 " option to specify a file to use instead.",
1304 "-e Terminate after receiving an <end cmd>",
1305 " in the data stream. Without this option,",
1306 " the receiver terminates only if an error",
1307 " is recognized or on EOF.",
1308 "-C|--chroot confine the process to <mount> using chroot",
1309 "--max-errors <N> Terminate as soon as N errors happened while",
1310 " processing commands from the send stream.",
1311 " Default value is 1. A value of 0 means no limit.",
1312 "-m <mountpoint> The root mount point of the destination fs.",
1313 " If you do not have /proc use this to tell us where ",
1314 " this file system is mounted.",