Btrfs progs v4.17.1
[btrfs-progs-unstable/devel.git] / cmds-send.c
blob16b9f8d2bf0b383027e2737f334db8568e78b361
1 /*
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"
22 #include <unistd.h>
23 #include <stdint.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <pthread.h>
27 #include <math.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <libgen.h>
32 #include <mntent.h>
33 #include <assert.h>
34 #include <getopt.h>
35 #include <uuid/uuid.h>
36 #include <limits.h>
38 #include "ctree.h"
39 #include "ioctl.h"
40 #include "commands.h"
41 #include "list.h"
42 #include "utils.h"
44 #include "send.h"
45 #include "send-utils.h"
46 #include "help.h"
48 #define SEND_BUFFER_SIZE SZ_64K
51 * Default is 1 for historical reasons, changing may break scripts that expect
52 * the 'At subvol' message.
54 static int g_verbose = 1;
56 struct btrfs_send {
57 int send_fd;
58 int dump_fd;
59 int mnt_fd;
61 u64 *clone_sources;
62 u64 clone_sources_count;
64 char *root_path;
65 struct subvol_uuid_search sus;
68 static int get_root_id(struct btrfs_send *sctx, const char *path, u64 *root_id)
70 struct subvol_info *si;
72 si = subvol_uuid_search(&sctx->sus, 0, NULL, 0, path,
73 subvol_search_by_path);
74 if (IS_ERR_OR_NULL(si)) {
75 if (!si)
76 return -ENOENT;
77 else
78 return PTR_ERR(si);
80 *root_id = si->root_id;
81 free(si->path);
82 free(si);
83 return 0;
86 static struct subvol_info *get_parent(struct btrfs_send *sctx, u64 root_id)
88 struct subvol_info *si_tmp;
89 struct subvol_info *si;
91 si_tmp = subvol_uuid_search(&sctx->sus, root_id, NULL, 0, NULL,
92 subvol_search_by_root_id);
93 if (IS_ERR_OR_NULL(si_tmp))
94 return si_tmp;
96 si = subvol_uuid_search(&sctx->sus, 0, si_tmp->parent_uuid, 0, NULL,
97 subvol_search_by_uuid);
98 free(si_tmp->path);
99 free(si_tmp);
100 return si;
103 static int find_good_parent(struct btrfs_send *sctx, u64 root_id, u64 *found)
105 int ret;
106 struct subvol_info *parent = NULL;
107 struct subvol_info *parent2 = NULL;
108 struct subvol_info *best_parent = NULL;
109 u64 best_diff = (u64)-1;
110 int i;
112 parent = get_parent(sctx, root_id);
113 if (IS_ERR_OR_NULL(parent)) {
114 if (!parent)
115 ret = -ENOENT;
116 else
117 ret = PTR_ERR(parent);
118 goto out;
121 for (i = 0; i < sctx->clone_sources_count; i++) {
122 if (sctx->clone_sources[i] == parent->root_id) {
123 best_parent = parent;
124 parent = NULL;
125 goto out_found;
129 for (i = 0; i < sctx->clone_sources_count; i++) {
130 s64 tmp;
132 parent2 = get_parent(sctx, sctx->clone_sources[i]);
133 if (IS_ERR_OR_NULL(parent2))
134 continue;
135 if (parent2->root_id != parent->root_id) {
136 free(parent2->path);
137 free(parent2);
138 parent2 = NULL;
139 continue;
142 free(parent2->path);
143 free(parent2);
144 parent2 = subvol_uuid_search(&sctx->sus,
145 sctx->clone_sources[i], NULL, 0, NULL,
146 subvol_search_by_root_id);
147 if (IS_ERR_OR_NULL(parent2)) {
148 if (!parent2)
149 ret = -ENOENT;
150 else
151 ret = PTR_ERR(parent2);
152 goto out;
154 tmp = parent2->ctransid - parent->ctransid;
155 if (tmp < 0)
156 tmp = -tmp;
157 if (tmp < best_diff) {
158 if (best_parent) {
159 free(best_parent->path);
160 free(best_parent);
162 best_parent = parent2;
163 parent2 = NULL;
164 best_diff = tmp;
165 } else {
166 free(parent2->path);
167 free(parent2);
168 parent2 = NULL;
172 if (!best_parent) {
173 ret = -ENOENT;
174 goto out;
177 out_found:
178 *found = best_parent->root_id;
179 ret = 0;
181 out:
182 if (parent) {
183 free(parent->path);
184 free(parent);
186 if (best_parent) {
187 free(best_parent->path);
188 free(best_parent);
190 return ret;
193 static int add_clone_source(struct btrfs_send *sctx, u64 root_id)
195 void *tmp;
197 tmp = sctx->clone_sources;
198 sctx->clone_sources = realloc(sctx->clone_sources,
199 sizeof(*sctx->clone_sources) * (sctx->clone_sources_count + 1));
201 if (!sctx->clone_sources) {
202 free(tmp);
203 return -ENOMEM;
205 sctx->clone_sources[sctx->clone_sources_count++] = root_id;
207 return 0;
210 #if 0
211 static int write_buf(int fd, const char *buf, size_t size)
213 int ret;
214 size_t pos = 0;
216 while (pos < size) {
217 ssize_t wbytes;
219 wbytes = write(fd, buf + pos, size - pos);
220 if (wbytes < 0) {
221 ret = -errno;
222 error("failed to dump stream: %s", strerror(-ret));
223 goto out;
225 if (!wbytes) {
226 ret = -EIO;
227 error("failed to dump stream: %s", strerror(-ret));
228 goto out;
230 pos += wbytes;
232 ret = 0;
234 out:
235 return ret;
238 static void* read_sent_data_copy(void *arg)
240 int ret;
241 struct btrfs_send *sctx = (struct btrfs_send*)arg;
242 char buf[SEND_BUFFER_SIZE];
244 while (1) {
245 ssize_t rbytes;
247 rbytes = read(sctx->send_fd, buf, sizeof(buf));
248 if (rbytes < 0) {
249 ret = -errno;
250 error("failed to read stream from kernel: %s",
251 strerror(-ret));
252 goto out;
254 if (!rbytes) {
255 ret = 0;
256 goto out;
258 ret = write_buf(sctx->dump_fd, buf, rbytes);
259 if (ret < 0)
260 goto out;
263 out:
264 if (ret < 0)
265 exit(-ret);
267 return ERR_PTR(ret);
269 #endif
271 static void *read_sent_data(void *arg)
273 int ret;
274 struct btrfs_send *sctx = (struct btrfs_send*)arg;
276 while (1) {
277 ssize_t sbytes;
279 /* Source is a pipe, output is either file or stdout */
280 sbytes = splice(sctx->send_fd, NULL, sctx->dump_fd,
281 NULL, SEND_BUFFER_SIZE, SPLICE_F_MORE);
282 if (sbytes < 0) {
283 ret = -errno;
284 error("failed to read stream from kernel: %s",
285 strerror(-ret));
286 goto out;
288 if (!sbytes) {
289 ret = 0;
290 goto out;
294 out:
295 if (ret < 0)
296 exit(-ret);
298 return ERR_PTR(ret);
301 static int do_send(struct btrfs_send *send, u64 parent_root_id,
302 int is_first_subvol, int is_last_subvol, const char *subvol,
303 u64 flags)
305 int ret;
306 pthread_t t_read;
307 struct btrfs_ioctl_send_args io_send;
308 void *t_err = NULL;
309 int subvol_fd = -1;
310 int pipefd[2] = {-1, -1};
312 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
313 if (subvol_fd < 0) {
314 ret = -errno;
315 error("cannot open %s: %s", subvol, strerror(-ret));
316 goto out;
319 ret = pipe(pipefd);
320 if (ret < 0) {
321 ret = -errno;
322 error("pipe failed: %s", strerror(-ret));
323 goto out;
326 memset(&io_send, 0, sizeof(io_send));
327 io_send.send_fd = pipefd[1];
328 send->send_fd = pipefd[0];
330 if (!ret)
331 ret = pthread_create(&t_read, NULL, read_sent_data, send);
332 if (ret) {
333 ret = -ret;
334 error("thread setup failed: %s", strerror(-ret));
335 goto out;
338 io_send.flags = flags;
339 io_send.clone_sources = (__u64*)send->clone_sources;
340 io_send.clone_sources_count = send->clone_sources_count;
341 io_send.parent_root = parent_root_id;
342 if (!is_first_subvol)
343 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
344 if (!is_last_subvol)
345 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
346 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
347 if (ret < 0) {
348 ret = -errno;
349 error("send ioctl failed with %d: %s", ret, strerror(-ret));
350 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
351 fprintf(stderr,
352 "Try upgrading your kernel or don't use -e.\n");
353 goto out;
355 if (g_verbose > 1)
356 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
358 if (g_verbose > 1)
359 fprintf(stderr, "joining genl thread\n");
361 close(pipefd[1]);
362 pipefd[1] = -1;
364 ret = pthread_join(t_read, &t_err);
365 if (ret) {
366 ret = -ret;
367 error("pthread_join failed: %s", strerror(-ret));
368 goto out;
370 if (t_err) {
371 ret = (long int)t_err;
372 error("failed to process send stream, ret=%ld (%s)",
373 (long int)t_err, strerror(-ret));
374 goto out;
377 ret = 0;
379 out:
380 if (subvol_fd != -1)
381 close(subvol_fd);
382 if (pipefd[0] != -1)
383 close(pipefd[0]);
384 if (pipefd[1] != -1)
385 close(pipefd[1]);
386 return ret;
389 static int init_root_path(struct btrfs_send *sctx, const char *subvol)
391 int ret = 0;
393 if (sctx->root_path)
394 goto out;
396 ret = find_mount_root(subvol, &sctx->root_path);
397 if (ret < 0) {
398 error("failed to determine mount point for %s: %s",
399 subvol, strerror(-ret));
400 ret = -EINVAL;
401 goto out;
403 if (ret > 0) {
404 error("%s doesn't belong to btrfs mount point", subvol);
405 ret = -EINVAL;
406 goto out;
409 sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME);
410 if (sctx->mnt_fd < 0) {
411 ret = -errno;
412 error("cannot open '%s': %s", sctx->root_path, strerror(-ret));
413 goto out;
416 ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus);
417 if (ret < 0) {
418 error("failed to initialize subvol search: %s",
419 strerror(-ret));
420 goto out;
423 out:
424 return ret;
428 static int is_subvol_ro(struct btrfs_send *sctx, const char *subvol)
430 int ret;
431 u64 flags;
432 int fd = -1;
434 fd = openat(sctx->mnt_fd, subvol, O_RDONLY | O_NOATIME);
435 if (fd < 0) {
436 ret = -errno;
437 error("cannot open %s: %s", subvol, strerror(-ret));
438 goto out;
441 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
442 if (ret < 0) {
443 ret = -errno;
444 error("failed to get flags for subvolume %s: %s",
445 subvol, strerror(-ret));
446 goto out;
449 if (flags & BTRFS_SUBVOL_RDONLY)
450 ret = 1;
451 else
452 ret = 0;
454 out:
455 if (fd != -1)
456 close(fd);
458 return ret;
461 static int set_root_info(struct btrfs_send *sctx, const char *subvol,
462 u64 *root_id)
464 int ret;
466 ret = init_root_path(sctx, subvol);
467 if (ret < 0)
468 goto out;
470 ret = get_root_id(sctx, subvol_strip_mountpoint(sctx->root_path, subvol),
471 root_id);
472 if (ret < 0) {
473 error("cannot resolve rootid for %s", subvol);
474 goto out;
477 out:
478 return ret;
481 static void free_send_info(struct btrfs_send *sctx)
483 if (sctx->mnt_fd >= 0) {
484 close(sctx->mnt_fd);
485 sctx->mnt_fd = -1;
487 free(sctx->root_path);
488 sctx->root_path = NULL;
489 subvol_uuid_search_finit(&sctx->sus);
492 int cmd_send(int argc, char **argv)
494 char *subvol = NULL;
495 int ret;
496 char outname[PATH_MAX];
497 struct btrfs_send send;
498 u32 i;
499 char *mount_root = NULL;
500 char *snapshot_parent = NULL;
501 u64 root_id = 0;
502 u64 parent_root_id = 0;
503 int full_send = 1;
504 int new_end_cmd_semantic = 0;
505 u64 send_flags = 0;
507 memset(&send, 0, sizeof(send));
508 send.dump_fd = fileno(stdout);
509 outname[0] = 0;
511 optind = 0;
512 while (1) {
513 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
514 static const struct option long_options[] = {
515 { "verbose", no_argument, NULL, 'v' },
516 { "quiet", no_argument, NULL, 'q' },
517 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
519 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
521 if (c < 0)
522 break;
524 switch (c) {
525 case 'v':
526 g_verbose++;
527 break;
528 case 'q':
529 g_verbose = 0;
530 break;
531 case 'e':
532 new_end_cmd_semantic = 1;
533 break;
534 case 'c':
535 subvol = realpath(optarg, NULL);
536 if (!subvol) {
537 ret = -errno;
538 error("realpath %s failed: %s\n", optarg, strerror(-ret));
539 goto out;
542 ret = set_root_info(&send, subvol, &root_id);
543 if (ret < 0)
544 goto out;
546 ret = is_subvol_ro(&send, subvol);
547 if (ret < 0)
548 goto out;
549 if (!ret) {
550 ret = -EINVAL;
551 error("cloned subvolume %s is not read-only", subvol);
552 goto out;
555 ret = add_clone_source(&send, root_id);
556 if (ret < 0) {
557 error("cannot add clone source: %s", strerror(-ret));
558 goto out;
560 free(subvol);
561 subvol = NULL;
562 free_send_info(&send);
563 full_send = 0;
564 break;
565 case 'f':
566 if (arg_copy_path(outname, optarg, sizeof(outname))) {
567 error("output file path too long (%zu)", strlen(optarg));
568 ret = 1;
569 goto out;
571 break;
572 case 'p':
573 if (snapshot_parent) {
574 error("you cannot have more than one parent (-p)");
575 ret = 1;
576 goto out;
578 snapshot_parent = realpath(optarg, NULL);
579 if (!snapshot_parent) {
580 ret = -errno;
581 error("realpath %s failed: %s", optarg, strerror(-ret));
582 goto out;
585 ret = is_subvol_ro(&send, snapshot_parent);
586 if (ret < 0)
587 goto out;
588 if (!ret) {
589 ret = -EINVAL;
590 error("parent subvolume %s is not read-only",
591 snapshot_parent);
592 goto out;
595 full_send = 0;
596 break;
597 case 'i':
598 error("option -i was removed, use -c instead");
599 ret = 1;
600 goto out;
601 case GETOPT_VAL_SEND_NO_DATA:
602 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
603 break;
604 case '?':
605 default:
606 error("send arguments invalid");
607 ret = 1;
608 goto out;
612 if (check_argc_min(argc - optind, 1))
613 usage(cmd_send_usage);
615 if (outname[0]) {
616 int tmpfd;
619 * Try to use an existing file first. Even if send runs as
620 * root, it might not have permissions to create file (eg. on a
621 * NFS) but it should still be able to use a pre-created file.
623 tmpfd = open(outname, O_WRONLY | O_TRUNC);
624 if (tmpfd < 0) {
625 if (errno == ENOENT)
626 tmpfd = open(outname,
627 O_CREAT | O_WRONLY | O_TRUNC, 0600);
629 send.dump_fd = tmpfd;
630 if (send.dump_fd == -1) {
631 ret = -errno;
632 error("cannot create '%s': %s", outname, strerror(-ret));
633 goto out;
637 if (isatty(send.dump_fd)) {
638 error(
639 "not dumping send stream into a terminal, redirect it into a file");
640 ret = 1;
641 goto out;
644 /* use first send subvol to determine mount_root */
645 subvol = realpath(argv[optind], NULL);
646 if (!subvol) {
647 ret = -errno;
648 error("unable to resolve %s", argv[optind]);
649 goto out;
652 ret = init_root_path(&send, subvol);
653 if (ret < 0)
654 goto out;
656 if (snapshot_parent != NULL) {
657 ret = get_root_id(&send,
658 subvol_strip_mountpoint(send.root_path, snapshot_parent),
659 &parent_root_id);
660 if (ret < 0) {
661 error("could not resolve rootid for %s", snapshot_parent);
662 goto out;
665 ret = add_clone_source(&send, parent_root_id);
666 if (ret < 0) {
667 error("cannot add clone source: %s", strerror(-ret));
668 goto out;
672 for (i = optind; i < argc; i++) {
673 free(subvol);
674 subvol = realpath(argv[i], NULL);
675 if (!subvol) {
676 ret = -errno;
677 error("unable to resolve %s", argv[i]);
678 goto out;
681 ret = find_mount_root(subvol, &mount_root);
682 if (ret < 0) {
683 error("find_mount_root failed on %s: %s", subvol,
684 strerror(-ret));
685 goto out;
687 if (ret > 0) {
688 error("%s does not belong to btrfs mount point",
689 subvol);
690 ret = -EINVAL;
691 goto out;
693 if (strcmp(send.root_path, mount_root) != 0) {
694 ret = -EINVAL;
695 error("all subvolumes must be from the same filesystem");
696 goto out;
698 free(mount_root);
700 ret = is_subvol_ro(&send, subvol);
701 if (ret < 0)
702 goto out;
703 if (!ret) {
704 ret = -EINVAL;
705 error("subvolume %s is not read-only", subvol);
706 goto out;
710 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
711 if (g_verbose > 1)
712 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
714 for (i = optind; i < argc; i++) {
715 int is_first_subvol;
716 int is_last_subvol;
718 free(subvol);
719 subvol = argv[i];
721 if (g_verbose > 0)
722 fprintf(stderr, "At subvol %s\n", subvol);
724 subvol = realpath(subvol, NULL);
725 if (!subvol) {
726 ret = -errno;
727 error("realpath %s failed: %s", argv[i], strerror(-ret));
728 goto out;
731 if (!full_send && !snapshot_parent) {
732 ret = set_root_info(&send, subvol, &root_id);
733 if (ret < 0)
734 goto out;
736 ret = find_good_parent(&send, root_id, &parent_root_id);
737 if (ret < 0) {
738 error("parent determination failed for %lld",
739 root_id);
740 goto out;
744 if (new_end_cmd_semantic) {
745 /* require new kernel */
746 is_first_subvol = (i == optind);
747 is_last_subvol = (i == argc - 1);
748 } else {
749 /* be compatible to old and new kernel */
750 is_first_subvol = 1;
751 is_last_subvol = 1;
753 ret = do_send(&send, parent_root_id, is_first_subvol,
754 is_last_subvol, subvol, send_flags);
755 if (ret < 0)
756 goto out;
758 if (!full_send && !snapshot_parent) {
759 /* done with this subvol, so add it to the clone sources */
760 ret = add_clone_source(&send, root_id);
761 if (ret < 0) {
762 error("cannot add clone source: %s", strerror(-ret));
763 goto out;
765 free_send_info(&send);
769 ret = 0;
771 out:
772 free(subvol);
773 free(snapshot_parent);
774 free(send.clone_sources);
775 free_send_info(&send);
776 return !!ret;
779 const char * const cmd_send_usage[] = {
780 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
781 "Send the subvolume(s) to stdout.",
782 "Sends the subvolume(s) specified by <subvol> to stdout.",
783 "<subvol> should be read-only here.",
784 "By default, this will send the whole subvolume. To do an incremental",
785 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
786 "any additional local snapshots, use '-c <clone-src>' (multiple times",
787 "where applicable). You must not specify clone sources unless you",
788 "guarantee that these snapshots are exactly in the same state on both",
789 "sides, the sender and the receiver. It is allowed to omit the",
790 "'-p <parent>' option when '-c <clone-src>' options are given, in",
791 "which case 'btrfs send' will determine a suitable parent among the",
792 "clone sources itself.",
793 "\n",
794 "-e If sending multiple subvols at once, use the new",
795 " format and omit the end-cmd between the subvols.",
796 "-p <parent> Send an incremental stream from <parent> to",
797 " <subvol>.",
798 "-c <clone-src> Use this snapshot as a clone source for an ",
799 " incremental send (multiple allowed)",
800 "-f <outfile> Output is normally written to stdout. To write to",
801 " a file, use this option. An alternative would be to",
802 " use pipes.",
803 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
804 " does not contain any file data and thus cannot be used",
805 " to transfer changes. This mode is faster and useful to",
806 " show the differences in metadata.",
807 "-v|--verbose enable verbose output to stderr, each occurrence of",
808 " this option increases verbosity",
809 "-q|--quiet suppress all messages, except errors",
810 NULL