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;
66 struct subvol_info *cur_subvol;
68 struct subvol_uuid_search sus;
73 static int finish_subvol(struct btrfs_receive *r)
77 struct btrfs_ioctl_received_subvol_args rs_args;
78 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
81 if (r->cur_subvol == NULL)
84 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
85 O_RDONLY | O_NOATIME);
88 fprintf(stderr, "ERROR: open %s failed. %s\n",
89 r->cur_subvol->path, strerror(-ret));
93 memset(&rs_args, 0, sizeof(rs_args));
94 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
95 rs_args.stransid = r->cur_subvol->stransid;
98 uuid_unparse((u8*)rs_args.uuid, uuid_str);
99 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
100 "stransid=%llu\n", uuid_str, rs_args.stransid);
103 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
106 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
110 r->cur_subvol->rtransid = rs_args.rtransid;
112 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
115 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
120 flags |= BTRFS_SUBVOL_RDONLY;
122 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
125 fprintf(stderr, "ERROR: failed to make subvolume read only. "
126 "%s\n", strerror(-ret));
134 free(r->cur_subvol->path);
136 r->cur_subvol = NULL;
143 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
147 struct btrfs_receive *r = user;
148 struct btrfs_ioctl_vol_args args_v1;
149 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
151 ret = finish_subvol(r);
155 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
157 if (strlen(r->dest_dir_path) == 0)
158 r->cur_subvol->path = strdup(path);
160 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
161 free(r->full_subvol_path);
162 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
164 fprintf(stderr, "At subvol %s\n", path);
166 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
167 r->cur_subvol->stransid = ctransid;
170 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
171 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
173 r->cur_subvol->stransid);
176 memset(&args_v1, 0, sizeof(args_v1));
177 strncpy_null(args_v1.name, path);
178 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
181 fprintf(stderr, "ERROR: creating subvolume %s failed. "
182 "%s\n", path, strerror(-ret));
190 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
191 const u8 *parent_uuid, u64 parent_ctransid,
195 struct btrfs_receive *r = user;
196 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
197 struct btrfs_ioctl_vol_args_v2 args_v2;
198 struct subvol_info *parent_subvol = NULL;
200 ret = finish_subvol(r);
204 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
206 if (strlen(r->dest_dir_path) == 0)
207 r->cur_subvol->path = strdup(path);
209 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
210 free(r->full_subvol_path);
211 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
213 fprintf(stdout, "At snapshot %s\n", path);
215 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
216 r->cur_subvol->stransid = ctransid;
219 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
220 fprintf(stderr, "receiving snapshot %s uuid=%s, "
221 "ctransid=%llu ", path, uuid_str,
222 r->cur_subvol->stransid);
223 uuid_unparse(parent_uuid, uuid_str);
224 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
225 uuid_str, parent_ctransid);
228 memset(&args_v2, 0, sizeof(args_v2));
229 strncpy_null(args_v2.name, path);
231 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
232 parent_ctransid, NULL, subvol_search_by_received_uuid);
233 if (!parent_subvol) {
234 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
235 parent_ctransid, NULL, subvol_search_by_uuid);
237 if (!parent_subvol) {
239 fprintf(stderr, "ERROR: could not find parent subvolume\n");
243 /*if (rs_args.ctransid > rs_args.rtransid) {
246 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
249 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
253 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
254 O_RDONLY | O_NOATIME);
255 if (args_v2.fd < 0) {
258 fprintf(stderr, "ERROR: open %s failed. %s\n",
259 parent_subvol->path, strerror(-ret));
262 "It seems that you have changed your default "
263 "subvolume or you specify other subvolume to\n"
264 "mount btrfs, try to remount this btrfs filesystem "
265 "with fs tree, and run btrfs receive again!\n");
269 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
273 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
274 "failed. %s\n", parent_subvol->path,
275 path, strerror(-ret));
281 free(parent_subvol->path);
287 static int process_mkfile(const char *path, void *user)
290 struct btrfs_receive *r = user;
291 char *full_path = path_cat(r->full_subvol_path, path);
294 fprintf(stderr, "mkfile %s\n", path);
296 ret = creat(full_path, 0600);
299 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
311 static int process_mkdir(const char *path, void *user)
314 struct btrfs_receive *r = user;
315 char *full_path = path_cat(r->full_subvol_path, path);
318 fprintf(stderr, "mkdir %s\n", path);
320 ret = mkdir(full_path, 0700);
323 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
331 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
334 struct btrfs_receive *r = user;
335 char *full_path = path_cat(r->full_subvol_path, path);
338 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
341 ret = mknod(full_path, mode & S_IFMT, dev);
344 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
352 static int process_mkfifo(const char *path, void *user)
355 struct btrfs_receive *r = user;
356 char *full_path = path_cat(r->full_subvol_path, path);
359 fprintf(stderr, "mkfifo %s\n", path);
361 ret = mkfifo(full_path, 0600);
364 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
372 static int process_mksock(const char *path, void *user)
375 struct btrfs_receive *r = user;
376 char *full_path = path_cat(r->full_subvol_path, path);
379 fprintf(stderr, "mksock %s\n", path);
381 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
384 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
392 static int process_symlink(const char *path, const char *lnk, void *user)
395 struct btrfs_receive *r = user;
396 char *full_path = path_cat(r->full_subvol_path, path);
399 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
401 ret = symlink(lnk, full_path);
404 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
405 lnk, strerror(-ret));
412 static int process_rename(const char *from, const char *to, void *user)
415 struct btrfs_receive *r = user;
416 char *full_from = path_cat(r->full_subvol_path, from);
417 char *full_to = path_cat(r->full_subvol_path, to);
420 fprintf(stderr, "rename %s -> %s\n", from, to);
422 ret = rename(full_from, full_to);
425 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
434 static int process_link(const char *path, const char *lnk, void *user)
437 struct btrfs_receive *r = user;
438 char *full_path = path_cat(r->full_subvol_path, path);
439 char *full_link_path = path_cat(r->full_subvol_path, lnk);
442 fprintf(stderr, "link %s -> %s\n", path, lnk);
444 ret = link(full_link_path, full_path);
447 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
448 lnk, strerror(-ret));
452 free(full_link_path);
457 static int process_unlink(const char *path, void *user)
460 struct btrfs_receive *r = user;
461 char *full_path = path_cat(r->full_subvol_path, path);
464 fprintf(stderr, "unlink %s\n", path);
466 ret = unlink(full_path);
469 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
477 static int process_rmdir(const char *path, void *user)
480 struct btrfs_receive *r = user;
481 char *full_path = path_cat(r->full_subvol_path, path);
484 fprintf(stderr, "rmdir %s\n", path);
486 ret = rmdir(full_path);
489 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
498 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
502 if (r->write_fd != -1) {
503 if (strcmp(r->write_path, path) == 0)
509 r->write_fd = open(path, O_RDWR);
510 if (r->write_fd < 0) {
512 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
517 r->write_path = strdup(path);
523 static void close_inode_for_write(struct btrfs_receive *r)
525 if(r->write_fd == -1)
530 r->write_path[0] = 0;
533 static int process_write(const char *path, const void *data, u64 offset,
537 struct btrfs_receive *r = user;
538 char *full_path = path_cat(r->full_subvol_path, path);
542 ret = open_inode_for_write(r, full_path);
547 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
551 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
552 path, strerror(-ret));
563 static int process_clone(const char *path, u64 offset, u64 len,
564 const u8 *clone_uuid, u64 clone_ctransid,
565 const char *clone_path, u64 clone_offset,
569 struct btrfs_receive *r = user;
570 struct btrfs_ioctl_clone_range_args clone_args;
571 struct subvol_info *si = NULL;
572 char *full_path = path_cat(r->full_subvol_path, path);
573 char *subvol_path = NULL;
574 char *full_clone_path = NULL;
577 ret = open_inode_for_write(r, full_path);
581 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
582 subvol_search_by_received_uuid);
584 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
585 BTRFS_UUID_SIZE) == 0) {
586 /* TODO check generation of extent */
587 subvol_path = strdup(r->cur_subvol->path);
590 fprintf(stderr, "ERROR: did not find source subvol.\n");
594 /*if (rs_args.ctransid > rs_args.rtransid) {
597 fprintf(stderr, "ERROR: subvolume %s was "
598 "modified after it was "
600 r->subvol_parent_name);
603 fprintf(stderr, "WARNING: subvolume %s was "
604 "modified after it was "
606 r->subvol_parent_name);
609 subvol_path = strdup(si->path);
612 full_clone_path = path_cat(subvol_path, clone_path);
614 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
617 fprintf(stderr, "ERROR: failed to open %s. %s\n",
618 full_clone_path, strerror(-ret));
622 clone_args.src_fd = clone_fd;
623 clone_args.src_offset = clone_offset;
624 clone_args.src_length = len;
625 clone_args.dest_offset = offset;
626 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
629 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
630 path, strerror(-ret));
640 free(full_clone_path);
648 static int process_set_xattr(const char *path, const char *name,
649 const void *data, int len, void *user)
652 struct btrfs_receive *r = user;
653 char *full_path = path_cat(r->full_subvol_path, path);
655 if (g_verbose >= 2) {
656 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
657 "data=%.*s\n", path, name, len,
661 ret = lsetxattr(full_path, name, data, len, 0);
664 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
665 path, name, len, (char*)data, strerror(-ret));
674 static int process_remove_xattr(const char *path, const char *name, void *user)
677 struct btrfs_receive *r = user;
678 char *full_path = path_cat(r->full_subvol_path, path);
680 if (g_verbose >= 2) {
681 fprintf(stderr, "remove_xattr %s - name=%s\n",
685 ret = lremovexattr(full_path, name);
688 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
689 path, name, strerror(-ret));
698 static int process_truncate(const char *path, u64 size, void *user)
701 struct btrfs_receive *r = user;
702 char *full_path = path_cat(r->full_subvol_path, path);
705 fprintf(stderr, "truncate %s size=%llu\n", path, size);
707 ret = truncate(full_path, size);
710 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
711 path, strerror(-ret));
720 static int process_chmod(const char *path, u64 mode, void *user)
723 struct btrfs_receive *r = user;
724 char *full_path = path_cat(r->full_subvol_path, path);
727 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
729 ret = chmod(full_path, mode);
732 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
733 path, strerror(-ret));
742 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
745 struct btrfs_receive *r = user;
746 char *full_path = path_cat(r->full_subvol_path, path);
749 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
752 ret = lchown(full_path, uid, gid);
755 fprintf(stderr, "ERROR: chown %s failed. %s\n",
756 path, strerror(-ret));
765 static int process_utimes(const char *path, struct timespec *at,
766 struct timespec *mt, struct timespec *ct,
770 struct btrfs_receive *r = user;
771 char *full_path = path_cat(r->full_subvol_path, path);
772 struct timespec tv[2];
775 fprintf(stderr, "utimes %s\n", path);
779 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
782 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
783 path, strerror(-ret));
793 static struct btrfs_send_ops send_ops = {
794 .subvol = process_subvol,
795 .snapshot = process_snapshot,
796 .mkfile = process_mkfile,
797 .mkdir = process_mkdir,
798 .mknod = process_mknod,
799 .mkfifo = process_mkfifo,
800 .mksock = process_mksock,
801 .symlink = process_symlink,
802 .rename = process_rename,
803 .link = process_link,
804 .unlink = process_unlink,
805 .rmdir = process_rmdir,
806 .write = process_write,
807 .clone = process_clone,
808 .set_xattr = process_set_xattr,
809 .remove_xattr = process_remove_xattr,
810 .truncate = process_truncate,
811 .chmod = process_chmod,
812 .chown = process_chown,
813 .utimes = process_utimes,
816 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
820 char *dest_dir_full_path;
823 dest_dir_full_path = realpath(tomnt, NULL);
824 if (!dest_dir_full_path) {
826 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
830 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
831 if (r->dest_dir_fd < 0) {
834 "ERROR: failed to open destination directory %s. %s\n",
835 dest_dir_full_path, strerror(-ret));
839 ret = find_mount_root(dest_dir_full_path, &r->root_path);
842 "ERROR: failed to determine mount point for %s: %s\n",
843 dest_dir_full_path, strerror(-ret));
849 "ERROR: %s doesn't belong to btrfs mount point\n",
854 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
857 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
862 if (r->dest_dir_chroot) {
863 if (chroot(dest_dir_full_path)) {
866 "ERROR: failed to chroot to %s, %s\n",
874 "ERROR: failed to chdir to /, %s\n",
878 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
879 r->root_path = strdup("/");
880 r->dest_dir_path = r->root_path;
883 * find_mount_root returns a root_path that is a subpath of
884 * dest_dir_full_path. Now get the other part of root_path,
885 * which is the destination dir relative to root_path.
887 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
888 while (r->dest_dir_path[0] == '/')
892 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
897 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
905 close_inode_for_write(r);
906 ret = finish_subvol(r);
913 if (r->write_fd != -1) {
920 r->write_path = NULL;
921 free(r->full_subvol_path);
922 r->full_subvol_path = NULL;
923 r->dest_dir_path = NULL;
924 free(dest_dir_full_path);
926 free(r->cur_subvol->path);
928 r->cur_subvol = NULL;
930 subvol_uuid_search_finit(&r->sus);
931 if (r->mnt_fd != -1) {
935 if (r->dest_dir_fd != -1) {
936 close(r->dest_dir_fd);
942 int cmd_receive(int argc, char **argv)
945 char *fromfile = NULL;
946 struct btrfs_receive r;
947 int receive_fd = fileno(stdin);
951 memset(&r, 0, sizeof(r));
955 r.dest_dir_chroot = 0;
959 static const struct option long_opts[] = {
960 { "max-errors", required_argument, NULL, 'E' },
961 { "chroot", no_argument, NULL, 'C' },
965 c = getopt_long(argc, argv, "Cevf:", long_opts, NULL);
980 r.dest_dir_chroot = 1;
983 max_errors = arg_strtou64(optarg);
987 fprintf(stderr, "ERROR: receive args invalid.\n");
992 if (check_argc_exact(argc - optind, 1))
993 usage(cmd_receive_usage);
995 tomnt = argv[optind];
998 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
999 if (receive_fd < 0) {
1000 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1005 ret = do_receive(&r, tomnt, receive_fd, max_errors);
1010 const char * const cmd_receive_usage[] = {
1011 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1012 "Receive subvolumes from stdin.",
1013 "Receives one or more subvolumes that were previously",
1014 "sent with btrfs send. The received subvolumes are stored",
1016 "btrfs receive will fail in case a receiving subvolume",
1017 "already exists. It will also fail in case a previously",
1018 "received subvolume was changed after it was received.",
1019 "After receiving a subvolume, it is immediately set to",
1021 "-v Enable verbose debug output. Each",
1022 " occurrence of this option increases the",
1023 " verbose level more.",
1024 "-f <infile> By default, btrfs receive uses stdin",
1025 " to receive the subvolumes. Use this",
1026 " option to specify a file to use instead.",
1027 "-e Terminate after receiving an <end cmd>",
1028 " in the data stream. Without this option,",
1029 " the receiver terminates only if an error",
1030 " is recognized or on EOF.",
1031 "-C|--chroot confine the process to <mount> using chroot",
1032 "--max-errors <N> Terminate as soon as N errors happened while",
1033 " processing commands from the send stream.",
1034 " Default value is 1. A value of 0 means no limit.",