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.
20 #include "kerncompat.h"
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
35 #include <uuid/uuid.h>
45 #include "send-utils.h"
47 #define SEND_BUFFER_SIZE (64 * 1024)
50 * Default is 1 for historical reasons, changing may break scripts that expect
51 * the 'At subvol' message.
53 static int g_verbose = 1;
61 u64 clone_sources_count;
64 struct subvol_uuid_search sus;
67 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
69 struct subvol_info *si;
71 si = subvol_uuid_search(&s->sus, 0, NULL, 0, path,
72 subvol_search_by_path);
75 *root_id = si->root_id;
81 static struct subvol_info *get_parent(struct btrfs_send *s, u64 root_id)
83 struct subvol_info *si_tmp;
84 struct subvol_info *si;
86 si_tmp = subvol_uuid_search(&s->sus, root_id, NULL, 0, NULL,
87 subvol_search_by_root_id);
91 si = subvol_uuid_search(&s->sus, 0, si_tmp->parent_uuid, 0, NULL,
92 subvol_search_by_uuid);
98 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
101 struct subvol_info *parent = NULL;
102 struct subvol_info *parent2 = NULL;
103 struct subvol_info *best_parent = NULL;
105 u64 best_diff = (u64)-1;
108 parent = get_parent(s, root_id);
114 for (i = 0; i < s->clone_sources_count; i++) {
115 if (s->clone_sources[i] == parent->root_id) {
116 best_parent = parent;
122 for (i = 0; i < s->clone_sources_count; i++) {
123 parent2 = get_parent(s, s->clone_sources[i]);
126 if (parent2->root_id != parent->root_id) {
135 parent2 = subvol_uuid_search(&s->sus, s->clone_sources[i], NULL,
136 0, NULL, subvol_search_by_root_id);
142 tmp = parent2->ctransid - parent->ctransid;
145 if (tmp < best_diff) {
147 free(best_parent->path);
150 best_parent = parent2;
166 *found = best_parent->root_id;
175 free(best_parent->path);
181 static int add_clone_source(struct btrfs_send *s, u64 root_id)
185 tmp = s->clone_sources;
186 s->clone_sources = realloc(s->clone_sources,
187 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
189 if (!s->clone_sources) {
193 s->clone_sources[s->clone_sources_count++] = root_id;
198 static int write_buf(int fd, const char *buf, size_t size)
206 wbytes = write(fd, buf + pos, size - pos);
209 error("failed to dump stream: %s", strerror(-ret));
214 error("failed to dump stream: %s", strerror(-ret));
225 static void *dump_thread(void *arg)
228 struct btrfs_send *sctx = (struct btrfs_send*)arg;
229 char buf[SEND_BUFFER_SIZE];
234 rbytes = read(sctx->send_fd, buf, sizeof(buf));
237 error("failed to read stream from kernel: %s\n",
245 ret = write_buf(sctx->dump_fd, buf, rbytes);
257 static int do_send(struct btrfs_send *send, u64 parent_root_id,
258 int is_first_subvol, int is_last_subvol, const char *subvol,
263 struct btrfs_ioctl_send_args io_send;
266 int pipefd[2] = {-1, -1};
268 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
271 error("cannot open %s: %s", subvol, strerror(-ret));
278 error("pipe failed: %s", strerror(-ret));
282 memset(&io_send, 0, sizeof(io_send));
283 io_send.send_fd = pipefd[1];
284 send->send_fd = pipefd[0];
287 ret = pthread_create(&t_read, NULL, dump_thread,
291 error("thread setup failed: %s", strerror(-ret));
295 io_send.flags = flags;
296 io_send.clone_sources = (__u64*)send->clone_sources;
297 io_send.clone_sources_count = send->clone_sources_count;
298 io_send.parent_root = parent_root_id;
299 if (!is_first_subvol)
300 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
302 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
303 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
306 error("send ioctl failed with %d: %s", ret, strerror(-ret));
307 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
309 "Try upgrading your kernel or don't use -e.\n");
313 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
316 fprintf(stderr, "joining genl thread\n");
321 ret = pthread_join(t_read, &t_err);
324 error("pthread_join failed: %s", strerror(-ret));
328 ret = (long int)t_err;
329 error("failed to process send stream, ret=%ld (%s)",
330 (long int)t_err, strerror(-ret));
346 static int init_root_path(struct btrfs_send *s, const char *subvol)
353 ret = find_mount_root(subvol, &s->root_path);
355 error("failed to determine mount point for %s: %s",
356 subvol, strerror(-ret));
361 error("%s doesn't belong to btrfs mount point", subvol);
366 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
369 error("cannot open '%s': %s", s->root_path, strerror(-ret));
373 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
375 error("failed to initialize subvol search: %s",
385 static int is_subvol_ro(struct btrfs_send *s, const char *subvol)
391 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
394 error("cannot open %s: %s", subvol, strerror(-ret));
398 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
401 error("failed to get flags for subvolume %s: %s",
402 subvol, strerror(-ret));
406 if (flags & BTRFS_SUBVOL_RDONLY)
418 int cmd_send(int argc, char **argv)
422 char outname[PATH_MAX];
423 struct btrfs_send send;
425 char *mount_root = NULL;
426 char *snapshot_parent = NULL;
428 u64 parent_root_id = 0;
430 int new_end_cmd_semantic = 0;
433 memset(&send, 0, sizeof(send));
434 send.dump_fd = fileno(stdout);
438 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
439 static const struct option long_options[] = {
440 { "verbose", no_argument, NULL, 'v' },
441 { "quiet", no_argument, NULL, 'q' },
442 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
444 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
457 new_end_cmd_semantic = 1;
460 subvol = realpath(optarg, NULL);
463 error("realpath %s failed: %s\n", optarg, strerror(-ret));
467 ret = init_root_path(&send, subvol);
471 ret = get_root_id(&send,
472 subvol_strip_mountpoint(send.root_path, subvol),
475 error("cannot resolve rootid for %s", subvol);
479 ret = is_subvol_ro(&send, subvol);
484 error("cloned subvolume %s is not read-only", subvol);
488 ret = add_clone_source(&send, root_id);
490 error("cannot add clone source: %s", strerror(-ret));
493 subvol_uuid_search_finit(&send.sus);
496 if (send.mnt_fd >= 0) {
500 free(send.root_path);
501 send.root_path = NULL;
505 if (arg_copy_path(outname, optarg, sizeof(outname))) {
506 error("output file path too long (%zu)", strlen(optarg));
512 if (snapshot_parent) {
513 error("you cannot have more than one parent (-p)");
517 snapshot_parent = realpath(optarg, NULL);
518 if (!snapshot_parent) {
520 error("realpath %s failed: %s", optarg, strerror(-ret));
524 ret = is_subvol_ro(&send, snapshot_parent);
529 error("parent subvolume %s is not read-only",
537 error("option -i was removed, use -c instead");
540 case GETOPT_VAL_SEND_NO_DATA:
541 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
545 error("send arguments invalid");
551 if (check_argc_min(argc - optind, 1))
552 usage(cmd_send_usage);
555 send.dump_fd = creat(outname, 0600);
556 if (send.dump_fd == -1) {
558 error("cannot create '%s': %s", outname, strerror(-ret));
563 if (isatty(send.dump_fd)) {
565 "not dumping send stream into a terminal, redirect it into a file");
570 /* use first send subvol to determine mount_root */
571 subvol = realpath(argv[optind], NULL);
574 error("unable to resolve %s", argv[optind]);
578 ret = init_root_path(&send, subvol);
582 if (snapshot_parent != NULL) {
583 ret = get_root_id(&send,
584 subvol_strip_mountpoint(send.root_path, snapshot_parent),
587 error("could not resolve rootid for %s", snapshot_parent);
591 ret = add_clone_source(&send, parent_root_id);
593 error("cannot add clone source: %s", strerror(-ret));
598 for (i = optind; i < argc; i++) {
600 subvol = realpath(argv[i], NULL);
603 error("unable to resolve %s", argv[i]);
607 ret = find_mount_root(subvol, &mount_root);
609 error("find_mount_root failed on %s: %s", subvol,
614 error("%s does not belong to btrfs mount point",
619 if (strcmp(send.root_path, mount_root) != 0) {
621 error("all subvolumes must be from the same filesystem");
626 ret = is_subvol_ro(&send, subvol);
631 error("subvolume %s is not read-only", subvol);
636 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
638 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
640 for (i = optind; i < argc; i++) {
648 fprintf(stderr, "At subvol %s\n", subvol);
650 subvol = realpath(subvol, NULL);
653 error("realpath %s failed: %s", argv[i], strerror(-ret));
657 if (!full_send && root_id) {
658 ret = find_good_parent(&send, root_id, &parent_root_id);
660 error("parent determination failed for %lld",
666 if (new_end_cmd_semantic) {
667 /* require new kernel */
668 is_first_subvol = (i == optind);
669 is_last_subvol = (i == argc - 1);
671 /* be compatible to old and new kernel */
675 ret = do_send(&send, parent_root_id, is_first_subvol,
676 is_last_subvol, subvol, send_flags);
680 if (!full_send && root_id) {
681 /* done with this subvol, so add it to the clone sources */
682 ret = add_clone_source(&send, root_id);
684 error("cannot add clone source: %s", strerror(-ret));
694 free(snapshot_parent);
695 free(send.clone_sources);
696 if (send.mnt_fd >= 0)
698 free(send.root_path);
699 subvol_uuid_search_finit(&send.sus);
703 const char * const cmd_send_usage[] = {
704 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
705 "Send the subvolume(s) to stdout.",
706 "Sends the subvolume(s) specified by <subvol> to stdout.",
707 "<subvol> should be read-only here.",
708 "By default, this will send the whole subvolume. To do an incremental",
709 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
710 "any additional local snapshots, use '-c <clone-src>' (multiple times",
711 "where applicable). You must not specify clone sources unless you",
712 "guarantee that these snapshots are exactly in the same state on both",
713 "sides, the sender and the receiver. It is allowed to omit the",
714 "'-p <parent>' option when '-c <clone-src>' options are given, in",
715 "which case 'btrfs send' will determine a suitable parent among the",
716 "clone sources itself.",
718 "-e If sending multiple subvols at once, use the new",
719 " format and omit the end-cmd between the subvols.",
720 "-p <parent> Send an incremental stream from <parent> to",
722 "-c <clone-src> Use this snapshot as a clone source for an ",
723 " incremental send (multiple allowed)",
724 "-f <outfile> Output is normally written to stdout. To write to",
725 " a file, use this option. An alternative would be to",
727 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
728 " does not contain any file data and thus cannot be used",
729 " to transfer changes. This mode is faster and useful to",
730 " show the differences in metadata.",
731 "-v|--verbose enable verbose output to stderr, each occurrence of",
732 " this option increases verbosity",
733 "-q|--quiet suppress all messages, except errors",