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[PATH_MAX];
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 ret = path_cat3_out(r->full_subvol_path, r->root_path,
170 r->dest_dir_path, path);
172 fprintf(stderr, "ERROR: subvol: path invalid: %s\n", path);
176 fprintf(stderr, "At subvol %s\n", path);
178 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
179 r->cur_subvol.stransid = ctransid;
182 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
183 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
185 r->cur_subvol.stransid);
188 memset(&args_v1, 0, sizeof(args_v1));
189 strncpy_null(args_v1.name, path);
190 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
193 fprintf(stderr, "ERROR: creating subvolume %s failed. "
194 "%s\n", path, strerror(-ret));
202 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
203 const u8 *parent_uuid, u64 parent_ctransid,
207 struct btrfs_receive *r = user;
208 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
209 struct btrfs_ioctl_vol_args_v2 args_v2;
210 struct subvol_info *parent_subvol = NULL;
212 ret = finish_subvol(r);
216 BUG_ON(r->cur_subvol.path);
218 if (strlen(r->dest_dir_path) == 0)
219 r->cur_subvol.path = strdup(path);
221 r->cur_subvol.path = path_cat(r->dest_dir_path, path);
222 ret = path_cat3_out(r->full_subvol_path, r->root_path,
223 r->dest_dir_path, path);
225 fprintf(stderr, "ERROR: snapshot: path invalid: %s\n", path);
229 fprintf(stdout, "At snapshot %s\n", path);
231 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
232 r->cur_subvol.stransid = ctransid;
235 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
236 fprintf(stderr, "receiving snapshot %s uuid=%s, "
237 "ctransid=%llu ", path, uuid_str,
238 r->cur_subvol.stransid);
239 uuid_unparse(parent_uuid, uuid_str);
240 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
241 uuid_str, parent_ctransid);
244 memset(&args_v2, 0, sizeof(args_v2));
245 strncpy_null(args_v2.name, path);
247 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
248 parent_ctransid, NULL, subvol_search_by_received_uuid);
249 if (!parent_subvol) {
250 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
251 parent_ctransid, NULL, subvol_search_by_uuid);
253 if (!parent_subvol) {
255 fprintf(stderr, "ERROR: could not find parent subvolume\n");
260 * The path is resolved from the root subvol, but we could be in some
261 * subvolume under the root subvolume, so try and adjust the path to be
262 * relative to our root path.
264 if (r->full_root_path) {
268 root_len = strlen(r->full_root_path);
269 sub_len = strlen(parent_subvol->path);
271 /* First make sure the parent subvol is actually in our path */
272 if (sub_len < root_len ||
273 strstr(parent_subvol->path, r->full_root_path) == NULL) {
274 fprintf(stderr, "ERROR: parent subvol is not reachable"
275 " from inside the root subvol.\n");
280 if (sub_len == root_len) {
281 parent_subvol->path[0] = '/';
282 parent_subvol->path[1] = '\0';
285 * root path is foo/bar
286 * subvol path is foo/bar/baz
288 * we need to have baz be the path, so we need to move
289 * the bit after foo/bar/, so path + root_len + 1, and
290 * move the part we care about, so sub_len - root_len -
293 memmove(parent_subvol->path,
294 parent_subvol->path + root_len + 1,
295 sub_len - root_len - 1);
296 parent_subvol->path[sub_len - root_len - 1] = '\0';
299 /*if (rs_args.ctransid > rs_args.rtransid) {
302 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
305 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
309 if (strlen(parent_subvol->path) == 0)
310 args_v2.fd = dup(r->mnt_fd);
312 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
313 O_RDONLY | O_NOATIME);
314 if (args_v2.fd < 0) {
317 fprintf(stderr, "ERROR: open %s failed. %s\n",
318 parent_subvol->path, strerror(-ret));
321 "It seems that you have changed your default "
322 "subvolume or you specify other subvolume to\n"
323 "mount btrfs, try to remount this btrfs filesystem "
324 "with fs tree, and run btrfs receive again!\n");
328 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
332 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
333 "failed. %s\n", parent_subvol->path,
334 path, strerror(-ret));
340 free(parent_subvol->path);
346 static int process_mkfile(const char *path, void *user)
349 struct btrfs_receive *r = user;
350 char full_path[PATH_MAX];
352 ret = path_cat_out(full_path, r->full_subvol_path, path);
354 fprintf(stderr, "ERROR: mkfile: path invalid: %s\n", path);
359 fprintf(stderr, "mkfile %s\n", path);
361 ret = creat(full_path, 0600);
364 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
375 static int process_mkdir(const char *path, void *user)
378 struct btrfs_receive *r = user;
379 char full_path[PATH_MAX];
381 ret = path_cat_out(full_path, r->full_subvol_path, path);
383 fprintf(stderr, "ERROR: mkdir: path invalid: %s\n", path);
388 fprintf(stderr, "mkdir %s\n", path);
390 ret = mkdir(full_path, 0700);
393 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
401 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
404 struct btrfs_receive *r = user;
405 char full_path[PATH_MAX];
407 ret = path_cat_out(full_path, r->full_subvol_path, path);
409 fprintf(stderr, "ERROR: mknod: path invalid: %s\n", path);
414 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
417 ret = mknod(full_path, mode & S_IFMT, dev);
420 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
428 static int process_mkfifo(const char *path, void *user)
431 struct btrfs_receive *r = user;
432 char full_path[PATH_MAX];
434 ret = path_cat_out(full_path, r->full_subvol_path, path);
436 fprintf(stderr, "ERROR: mkfifo: path invalid: %s\n", path);
441 fprintf(stderr, "mkfifo %s\n", path);
443 ret = mkfifo(full_path, 0600);
446 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
454 static int process_mksock(const char *path, void *user)
457 struct btrfs_receive *r = user;
458 char full_path[PATH_MAX];
460 ret = path_cat_out(full_path, r->full_subvol_path, path);
462 fprintf(stderr, "ERROR: mksock: path invalid: %s\n", path);
467 fprintf(stderr, "mksock %s\n", path);
469 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
472 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
480 static int process_symlink(const char *path, const char *lnk, void *user)
483 struct btrfs_receive *r = user;
484 char full_path[PATH_MAX];
486 ret = path_cat_out(full_path, r->full_subvol_path, path);
488 fprintf(stderr, "ERROR: symlink: path invalid: %s\n", path);
493 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
495 ret = symlink(lnk, full_path);
498 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
499 lnk, strerror(-ret));
506 static int process_rename(const char *from, const char *to, void *user)
509 struct btrfs_receive *r = user;
510 char full_from[PATH_MAX];
511 char full_to[PATH_MAX];
513 ret = path_cat_out(full_from, r->full_subvol_path, from);
515 fprintf(stderr, "ERROR: rename: source path invalid: %s\n",
520 ret = path_cat_out(full_to, r->full_subvol_path, to);
522 fprintf(stderr, "ERROR: rename: target path invalid: %s\n",
528 fprintf(stderr, "rename %s -> %s\n", from, to);
530 ret = rename(full_from, full_to);
533 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
541 static int process_link(const char *path, const char *lnk, void *user)
544 struct btrfs_receive *r = user;
545 char full_path[PATH_MAX];
546 char full_link_path[PATH_MAX];
548 ret = path_cat_out(full_path, r->full_subvol_path, path);
550 fprintf(stderr, "ERROR: link: source path invalid: %s\n",
555 ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
557 fprintf(stderr, "ERROR: link: target path invalid: %s\n",
563 fprintf(stderr, "link %s -> %s\n", path, lnk);
565 ret = link(full_link_path, full_path);
568 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
569 lnk, strerror(-ret));
577 static int process_unlink(const char *path, void *user)
580 struct btrfs_receive *r = user;
581 char full_path[PATH_MAX];
583 ret = path_cat_out(full_path, r->full_subvol_path, path);
585 fprintf(stderr, "ERROR: unlink: path invalid: %s\n", path);
590 fprintf(stderr, "unlink %s\n", path);
592 ret = unlink(full_path);
595 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
603 static int process_rmdir(const char *path, void *user)
606 struct btrfs_receive *r = user;
607 char full_path[PATH_MAX];
609 ret = path_cat_out(full_path, r->full_subvol_path, path);
611 fprintf(stderr, "ERROR: rmdir: path invalid: %s\n", path);
616 fprintf(stderr, "rmdir %s\n", path);
618 ret = rmdir(full_path);
621 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
629 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
633 if (r->write_fd != -1) {
634 if (strcmp(r->write_path, path) == 0)
640 r->write_fd = open(path, O_RDWR);
641 if (r->write_fd < 0) {
643 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
647 strncpy_null(r->write_path, path);
653 static void close_inode_for_write(struct btrfs_receive *r)
655 if(r->write_fd == -1)
660 r->write_path[0] = 0;
663 static int process_write(const char *path, const void *data, u64 offset,
667 struct btrfs_receive *r = user;
668 char full_path[PATH_MAX];
672 ret = path_cat_out(full_path, r->full_subvol_path, path);
674 fprintf(stderr, "ERROR: write: path invalid: %s\n", path);
678 ret = open_inode_for_write(r, full_path);
683 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
687 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
688 path, strerror(-ret));
698 static int process_clone(const char *path, u64 offset, u64 len,
699 const u8 *clone_uuid, u64 clone_ctransid,
700 const char *clone_path, u64 clone_offset,
704 struct btrfs_receive *r = user;
705 struct btrfs_ioctl_clone_range_args clone_args;
706 struct subvol_info *si = NULL;
707 char full_path[PATH_MAX];
708 char *subvol_path = NULL;
709 char full_clone_path[PATH_MAX];
712 ret = path_cat_out(full_path, r->full_subvol_path, path);
714 fprintf(stderr, "ERROR: clone: source path invalid: %s\n",
719 ret = open_inode_for_write(r, full_path);
723 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
724 subvol_search_by_received_uuid);
726 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
727 BTRFS_UUID_SIZE) == 0) {
728 /* TODO check generation of extent */
729 subvol_path = strdup(r->cur_subvol.path);
732 fprintf(stderr, "ERROR: did not find source subvol.\n");
736 /*if (rs_args.ctransid > rs_args.rtransid) {
739 fprintf(stderr, "ERROR: subvolume %s was "
740 "modified after it was "
742 r->subvol_parent_name);
745 fprintf(stderr, "WARNING: subvolume %s was "
746 "modified after it was "
748 r->subvol_parent_name);
751 subvol_path = strdup(si->path);
754 ret = path_cat_out(full_clone_path, subvol_path, clone_path);
756 fprintf(stderr, "ERROR: clone: target path invalid: %s\n",
761 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
764 fprintf(stderr, "ERROR: failed to open %s. %s\n",
765 full_clone_path, strerror(-ret));
769 clone_args.src_fd = clone_fd;
770 clone_args.src_offset = clone_offset;
771 clone_args.src_length = len;
772 clone_args.dest_offset = offset;
773 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
776 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
777 path, strerror(-ret));
793 static int process_set_xattr(const char *path, const char *name,
794 const void *data, int len, void *user)
797 struct btrfs_receive *r = user;
798 char full_path[PATH_MAX];
800 ret = path_cat_out(full_path, r->full_subvol_path, path);
802 fprintf(stderr, "ERROR: set_xattr: path invalid: %s\n", path);
806 if (strcmp("security.capability", name) == 0) {
808 fprintf(stderr, "set_xattr: cache capabilities\n");
809 if (r->cached_capabilities_len)
811 "WARNING: capabilities set multiple times per file: %s\n",
813 if (len > sizeof(r->cached_capabilities)) {
815 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
820 r->cached_capabilities_len = len;
821 memcpy(r->cached_capabilities, data, len);
824 if (g_verbose >= 2) {
825 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
826 "data=%.*s\n", path, name, len,
830 ret = lsetxattr(full_path, name, data, len, 0);
833 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
834 path, name, len, (char*)data, strerror(-ret));
842 static int process_remove_xattr(const char *path, const char *name, void *user)
845 struct btrfs_receive *r = user;
846 char full_path[PATH_MAX];
848 ret = path_cat_out(full_path, r->full_subvol_path, path);
850 fprintf(stderr, "ERROR: remove_xattr: path invalid: %s\n",
855 if (g_verbose >= 2) {
856 fprintf(stderr, "remove_xattr %s - name=%s\n",
860 ret = lremovexattr(full_path, name);
863 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
864 path, name, strerror(-ret));
872 static int process_truncate(const char *path, u64 size, void *user)
875 struct btrfs_receive *r = user;
876 char full_path[PATH_MAX];
878 ret = path_cat_out(full_path, r->full_subvol_path, path);
880 fprintf(stderr, "ERROR: truncate: path invalid: %s\n", path);
885 fprintf(stderr, "truncate %s size=%llu\n", path, size);
887 ret = truncate(full_path, size);
890 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
891 path, strerror(-ret));
899 static int process_chmod(const char *path, u64 mode, void *user)
902 struct btrfs_receive *r = user;
903 char full_path[PATH_MAX];
905 ret = path_cat_out(full_path, r->full_subvol_path, path);
907 fprintf(stderr, "ERROR: chmod: path invalid: %s\n", path);
912 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
914 ret = chmod(full_path, mode);
917 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
918 path, strerror(-ret));
926 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
929 struct btrfs_receive *r = user;
930 char full_path[PATH_MAX];
932 ret = path_cat_out(full_path, r->full_subvol_path, path);
934 fprintf(stderr, "ERROR: chown: path invalid: %s\n", path);
939 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
942 ret = lchown(full_path, uid, gid);
945 fprintf(stderr, "ERROR: chown %s failed. %s\n",
946 path, strerror(-ret));
950 if (r->cached_capabilities_len) {
952 fprintf(stderr, "chown: restore capabilities\n");
953 ret = lsetxattr(full_path, "security.capability",
954 r->cached_capabilities,
955 r->cached_capabilities_len, 0);
956 memset(r->cached_capabilities, 0,
957 sizeof(r->cached_capabilities));
958 r->cached_capabilities_len = 0;
961 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
962 path, strerror(-ret));
971 static int process_utimes(const char *path, struct timespec *at,
972 struct timespec *mt, struct timespec *ct,
976 struct btrfs_receive *r = user;
977 char full_path[PATH_MAX];
978 struct timespec tv[2];
980 ret = path_cat_out(full_path, r->full_subvol_path, path);
982 fprintf(stderr, "ERROR: utimes: path invalid: %s\n", path);
987 fprintf(stderr, "utimes %s\n", path);
991 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
994 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
995 path, strerror(-ret));
1003 static int process_update_extent(const char *path, u64 offset, u64 len,
1007 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1008 path, (unsigned long long)offset,
1009 (unsigned long long)len);
1012 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1018 static struct btrfs_send_ops send_ops = {
1019 .subvol = process_subvol,
1020 .snapshot = process_snapshot,
1021 .mkfile = process_mkfile,
1022 .mkdir = process_mkdir,
1023 .mknod = process_mknod,
1024 .mkfifo = process_mkfifo,
1025 .mksock = process_mksock,
1026 .symlink = process_symlink,
1027 .rename = process_rename,
1028 .link = process_link,
1029 .unlink = process_unlink,
1030 .rmdir = process_rmdir,
1031 .write = process_write,
1032 .clone = process_clone,
1033 .set_xattr = process_set_xattr,
1034 .remove_xattr = process_remove_xattr,
1035 .truncate = process_truncate,
1036 .chmod = process_chmod,
1037 .chown = process_chown,
1038 .utimes = process_utimes,
1039 .update_extent = process_update_extent,
1042 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1043 char *realmnt, int r_fd, u64 max_errors)
1047 char *dest_dir_full_path;
1048 char root_subvol_path[PATH_MAX];
1051 dest_dir_full_path = realpath(tomnt, NULL);
1052 if (!dest_dir_full_path) {
1054 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
1058 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1059 if (r->dest_dir_fd < 0) {
1062 "ERROR: failed to open destination directory %s. %s\n",
1063 dest_dir_full_path, strerror(-ret));
1068 r->root_path = realmnt;
1070 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1073 "ERROR: failed to determine mount point for %s: %s\n",
1074 dest_dir_full_path, strerror(-ret));
1080 "ERROR: %s doesn't belong to btrfs mount point\n",
1081 dest_dir_full_path);
1086 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1087 if (r->mnt_fd < 0) {
1089 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
1095 * If we use -m or a default subvol we want to resolve the path to the
1096 * subvolume we're sitting in so that we can adjust the paths of any
1097 * subvols we want to receive in.
1099 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1101 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
1106 root_subvol_path[0] = 0;
1107 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1108 PATH_MAX, subvol_id);
1110 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
1115 * Ok we're inside of a subvol off of the root subvol, we need to
1116 * actually set full_root_path.
1118 if (strlen(root_subvol_path))
1119 r->full_root_path = root_subvol_path;
1121 if (r->dest_dir_chroot) {
1122 if (chroot(dest_dir_full_path)) {
1125 "ERROR: failed to chroot to %s, %s\n",
1133 "ERROR: failed to chdir to /, %s\n",
1137 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1138 r->root_path = strdup("/");
1139 r->dest_dir_path = r->root_path;
1142 * find_mount_root returns a root_path that is a subpath of
1143 * dest_dir_full_path. Now get the other part of root_path,
1144 * which is the destination dir relative to root_path.
1146 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1147 while (r->dest_dir_path[0] == '/')
1151 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1156 if (r->cached_capabilities_len) {
1158 fprintf(stderr, "clear cached capabilities\n");
1159 memset(r->cached_capabilities, 0,
1160 sizeof(r->cached_capabilities));
1161 r->cached_capabilities_len = 0;
1164 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1172 close_inode_for_write(r);
1173 ret = finish_subvol(r);
1180 if (r->write_fd != -1) {
1185 r->root_path = NULL;
1186 r->dest_dir_path = NULL;
1187 free(dest_dir_full_path);
1188 if (r->cur_subvol.path) {
1189 free(r->cur_subvol.path);
1190 r->cur_subvol.path = NULL;
1192 subvol_uuid_search_finit(&r->sus);
1193 if (r->mnt_fd != -1) {
1197 if (r->dest_dir_fd != -1) {
1198 close(r->dest_dir_fd);
1199 r->dest_dir_fd = -1;
1205 int cmd_receive(int argc, char **argv)
1208 char fromfile[PATH_MAX];
1209 char realmnt[PATH_MAX];
1210 struct btrfs_receive r;
1211 int receive_fd = fileno(stdin);
1215 memset(&r, 0, sizeof(r));
1219 r.dest_dir_chroot = 0;
1225 static const struct option long_opts[] = {
1226 { "max-errors", required_argument, NULL, 'E' },
1227 { "chroot", no_argument, NULL, 'C' },
1228 { NULL, 0, NULL, 0 }
1231 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1240 if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1242 "ERROR: input file path too long (%zu)\n",
1249 r.honor_end_cmd = 1;
1252 r.dest_dir_chroot = 1;
1255 max_errors = arg_strtou64(optarg);
1258 if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1260 "ERROR: mount point path too long (%zu)\n",
1268 fprintf(stderr, "ERROR: receive args invalid.\n");
1273 if (check_argc_exact(argc - optind, 1))
1274 usage(cmd_receive_usage);
1276 tomnt = argv[optind];
1279 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1280 if (receive_fd < 0) {
1281 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1286 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1293 const char * const cmd_receive_usage[] = {
1294 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1295 "Receive subvolumes from stdin.",
1296 "Receives one or more subvolumes that were previously",
1297 "sent with btrfs send. The received subvolumes are stored",
1299 "btrfs receive will fail in case a receiving subvolume",
1300 "already exists. It will also fail in case a previously",
1301 "received subvolume was changed after it was received.",
1302 "After receiving a subvolume, it is immediately set to",
1304 "-v Enable verbose debug output. Each",
1305 " occurrence of this option increases the",
1306 " verbose level more.",
1307 "-f <infile> By default, btrfs receive uses stdin",
1308 " to receive the subvolumes. Use this",
1309 " option to specify a file to use instead.",
1310 "-e Terminate after receiving an <end cmd>",
1311 " in the data stream. Without this option,",
1312 " the receiver terminates only if an error",
1313 " is recognized or on EOF.",
1314 "-C|--chroot confine the process to <mount> using chroot",
1315 "--max-errors <N> Terminate as soon as N errors happened while",
1316 " processing commands from the send stream.",
1317 " Default value is 1. A value of 0 means no limit.",
1318 "-m <mountpoint> The root mount point of the destination fs.",
1319 " If you do not have /proc use this to tell us where ",
1320 " this file system is mounted.",