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 static int g_verbose = 0;
55 u64 clone_sources_count;
58 struct subvol_uuid_search sus;
61 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
63 struct subvol_info *si;
65 si = subvol_uuid_search(&s->sus, 0, NULL, 0, path,
66 subvol_search_by_path);
69 *root_id = si->root_id;
75 static struct subvol_info *get_parent(struct btrfs_send *s, u64 root_id)
77 struct subvol_info *si_tmp;
78 struct subvol_info *si;
80 si_tmp = subvol_uuid_search(&s->sus, root_id, NULL, 0, NULL,
81 subvol_search_by_root_id);
85 si = subvol_uuid_search(&s->sus, 0, si_tmp->parent_uuid, 0, NULL,
86 subvol_search_by_uuid);
92 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
95 struct subvol_info *parent = NULL;
96 struct subvol_info *parent2 = NULL;
97 struct subvol_info *best_parent = NULL;
99 u64 best_diff = (u64)-1;
102 parent = get_parent(s, root_id);
108 for (i = 0; i < s->clone_sources_count; i++) {
109 if (s->clone_sources[i] == parent->root_id) {
110 best_parent = parent;
116 for (i = 0; i < s->clone_sources_count; i++) {
117 parent2 = get_parent(s, s->clone_sources[i]);
120 if (parent2->root_id != parent->root_id) {
129 parent2 = subvol_uuid_search(&s->sus, s->clone_sources[i], NULL,
130 0, NULL, subvol_search_by_root_id);
136 tmp = parent2->ctransid - parent->ctransid;
139 if (tmp < best_diff) {
141 free(best_parent->path);
144 best_parent = parent2;
160 *found = best_parent->root_id;
169 free(best_parent->path);
175 static int add_clone_source(struct btrfs_send *s, u64 root_id)
179 tmp = s->clone_sources;
180 s->clone_sources = realloc(s->clone_sources,
181 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
183 if (!s->clone_sources) {
187 s->clone_sources[s->clone_sources_count++] = root_id;
192 static int write_buf(int fd, const void *buf, int size)
198 ret = write(fd, (char*)buf + pos, size - pos);
201 error("failed to dump stream: %s", strerror(-ret));
206 error("failed to dump stream: %s", strerror(-ret));
217 static void *dump_thread(void *arg_)
220 struct btrfs_send *s = (struct btrfs_send*)arg_;
225 readed = read(s->send_fd, buf, sizeof(buf));
228 error("failed to read stream from kernel: %s\n",
236 ret = write_buf(s->dump_fd, buf, readed);
249 static int do_send(struct btrfs_send *send, u64 parent_root_id,
250 int is_first_subvol, int is_last_subvol, char *subvol,
255 struct btrfs_ioctl_send_args io_send;
258 int pipefd[2] = {-1, -1};
260 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
263 error("cannot open %s: %s", subvol, strerror(-ret));
270 error("pipe failed: %s", strerror(-ret));
274 memset(&io_send, 0, sizeof(io_send));
275 io_send.send_fd = pipefd[1];
276 send->send_fd = pipefd[0];
279 ret = pthread_create(&t_read, NULL, dump_thread,
283 error("thread setup failed: %s", strerror(-ret));
287 io_send.flags = flags;
288 io_send.clone_sources = (__u64*)send->clone_sources;
289 io_send.clone_sources_count = send->clone_sources_count;
290 io_send.parent_root = parent_root_id;
291 if (!is_first_subvol)
292 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
294 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
295 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
298 error("send ioctl failed with %d: %s", ret, strerror(-ret));
299 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
301 "Try upgrading your kernel or don't use -e.\n");
305 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
308 fprintf(stderr, "joining genl thread\n");
313 ret = pthread_join(t_read, &t_err);
316 error("pthread_join failed: %s", strerror(-ret));
320 ret = (long int)t_err;
321 error("failed to process send stream, ret=%ld (%s)",
322 (long int)t_err, strerror(-ret));
338 char *get_subvol_name(char *mnt, char *full_path)
340 int len = strlen(mnt);
343 if (mnt[len - 1] != '/')
346 return full_path + len;
349 static int init_root_path(struct btrfs_send *s, const char *subvol)
356 ret = find_mount_root(subvol, &s->root_path);
358 error("failed to determine mount point for %s: %s",
359 subvol, strerror(-ret));
364 error("%s doesn't belong to btrfs mount point", subvol);
369 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
372 error("cannot open '%s': %s", s->root_path, strerror(-ret));
376 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
378 error("failed to initialize subvol search: %s",
388 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
394 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
397 error("cannot open %s: %s", subvol, strerror(-ret));
401 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
404 error("failed to get flags for subvolume %s: %s",
405 subvol, strerror(-ret));
409 if (flags & BTRFS_SUBVOL_RDONLY)
421 int cmd_send(int argc, char **argv)
425 char outname[PATH_MAX];
426 struct btrfs_send send;
428 char *mount_root = NULL;
429 char *snapshot_parent = NULL;
431 u64 parent_root_id = 0;
433 int new_end_cmd_semantic = 0;
436 memset(&send, 0, sizeof(send));
437 send.dump_fd = fileno(stdout);
441 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
442 static const struct option long_options[] = {
443 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
445 int c = getopt_long(argc, argv, "vec:f:i:p:", long_options, NULL);
455 new_end_cmd_semantic = 1;
458 subvol = realpath(optarg, NULL);
461 error("realpath %s failed: %s\n", optarg, strerror(-ret));
465 ret = init_root_path(&send, subvol);
469 ret = get_root_id(&send, get_subvol_name(send.root_path, subvol),
472 error("cannot resolve rootid for %s", subvol);
476 ret = is_subvol_ro(&send, subvol);
481 error("cloned subvolume %s is not read-only", subvol);
485 ret = add_clone_source(&send, root_id);
487 error("not enough memory");
490 subvol_uuid_search_finit(&send.sus);
493 if (send.mnt_fd >= 0) {
497 free(send.root_path);
498 send.root_path = NULL;
502 if (arg_copy_path(outname, optarg, sizeof(outname))) {
503 error("output file path too long (%zu)", strlen(optarg));
509 if (snapshot_parent) {
510 error("you cannot have more than one parent (-p)");
514 snapshot_parent = realpath(optarg, NULL);
515 if (!snapshot_parent) {
517 error("realpath %s failed: %s", optarg, strerror(-ret));
521 ret = is_subvol_ro(&send, snapshot_parent);
526 error("parent subvolume %s is not read-only",
534 error("option -i was removed, use -c instead");
537 case GETOPT_VAL_SEND_NO_DATA:
538 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
542 error("send arguments invalid");
548 if (check_argc_min(argc - optind, 1))
549 usage(cmd_send_usage);
552 send.dump_fd = creat(outname, 0600);
553 if (send.dump_fd == -1) {
555 error("cannot create '%s': %s", outname, strerror(-ret));
560 if (isatty(send.dump_fd)) {
562 "not dumping send stream into a terminal, redirect it into a file");
567 /* use first send subvol to determine mount_root */
568 subvol = argv[optind];
570 subvol = realpath(argv[optind], NULL);
573 error("unable to resolve %s", argv[optind]);
577 ret = init_root_path(&send, subvol);
581 if (snapshot_parent != NULL) {
582 ret = get_root_id(&send,
583 get_subvol_name(send.root_path, snapshot_parent),
586 error("could not resolve rootid for %s", snapshot_parent);
590 ret = add_clone_source(&send, parent_root_id);
592 error("not enough memory");
597 for (i = optind; i < argc; i++) {
599 subvol = realpath(argv[i], NULL);
602 error("unable to resolve %s", argv[i]);
606 ret = find_mount_root(subvol, &mount_root);
608 error("find_mount_root failed on %s: %s", subvol,
613 error("%s does not belong to btrfs mount point",
618 if (strcmp(send.root_path, mount_root) != 0) {
620 error("all subvolumes must be from the same filesystem");
625 ret = is_subvol_ro(&send, subvol);
630 error("subvolum %s is not read-only", subvol);
635 if (send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
636 printf("Mode NO_FILE_DATA enabled\n");
638 for (i = optind; i < argc; i++) {
645 fprintf(stderr, "At subvol %s\n", subvol);
647 subvol = realpath(subvol, NULL);
650 error("realpath %s failed: %s", argv[i], strerror(-ret));
654 if (!full_send && !parent_root_id) {
655 ret = find_good_parent(&send, root_id, &parent_root_id);
657 error("parent determination failed for %lld",
663 ret = is_subvol_ro(&send, subvol);
668 error("subvolume %s is not read-only", subvol);
672 if (new_end_cmd_semantic) {
673 /* require new kernel */
674 is_first_subvol = (i == optind);
675 is_last_subvol = (i == argc - 1);
677 /* be compatible to old and new kernel */
681 ret = do_send(&send, parent_root_id, is_first_subvol,
682 is_last_subvol, subvol, send_flags);
686 /* done with this subvol, so add it to the clone sources */
687 ret = add_clone_source(&send, root_id);
689 error("not enough memory");
701 free(snapshot_parent);
702 free(send.clone_sources);
703 if (send.mnt_fd >= 0)
705 free(send.root_path);
706 subvol_uuid_search_finit(&send.sus);
710 const char * const cmd_send_usage[] = {
711 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
712 "Send the subvolume(s) to stdout.",
713 "Sends the subvolume(s) specified by <subvol> to stdout.",
714 "<subvol> should be read-only here.",
715 "By default, this will send the whole subvolume. To do an incremental",
716 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
717 "any additional local snapshots, use '-c <clone-src>' (multiple times",
718 "where applicable). You must not specify clone sources unless you",
719 "guarantee that these snapshots are exactly in the same state on both",
720 "sides, the sender and the receiver. It is allowed to omit the",
721 "'-p <parent>' option when '-c <clone-src>' options are given, in",
722 "which case 'btrfs send' will determine a suitable parent among the",
723 "clone sources itself.",
725 "-v Enable verbose debug output. Each occurrence of",
726 " this option increases the verbose level more.",
727 "-e If sending multiple subvols at once, use the new",
728 " format and omit the end-cmd between the subvols.",
729 "-p <parent> Send an incremental stream from <parent> to",
731 "-c <clone-src> Use this snapshot as a clone source for an ",
732 " incremental send (multiple allowed)",
733 "-f <outfile> Output is normally written to stdout. To write to",
734 " a file, use this option. An alternative would be to",
736 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
737 " does not contain any file data and thus cannot be used",
738 " to transfer changes. This mode is faster and useful to",
739 " show the differences in metadata.",