btrfs-progs: Add all missing btrfs_close_all_devices to standalone tools
[btrfs-progs-unstable/devel.git] / cmds-send.c
blob581b25e57813fd2e8995529468dd6f7d760dd55b
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"
47 static int g_verbose = 0;
49 struct btrfs_send {
50 int send_fd;
51 int dump_fd;
52 int mnt_fd;
54 u64 *clone_sources;
55 u64 clone_sources_count;
57 char *root_path;
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);
67 if (!si)
68 return -ENOENT;
69 *root_id = si->root_id;
70 free(si->path);
71 free(si);
72 return 0;
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);
82 if (!si_tmp)
83 return NULL;
85 si = subvol_uuid_search(&s->sus, 0, si_tmp->parent_uuid, 0, NULL,
86 subvol_search_by_uuid);
87 free(si_tmp->path);
88 free(si_tmp);
89 return si;
92 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
94 int ret;
95 struct subvol_info *parent = NULL;
96 struct subvol_info *parent2 = NULL;
97 struct subvol_info *best_parent = NULL;
98 __s64 tmp;
99 u64 best_diff = (u64)-1;
100 int i;
102 parent = get_parent(s, root_id);
103 if (!parent) {
104 ret = -ENOENT;
105 goto out;
108 for (i = 0; i < s->clone_sources_count; i++) {
109 if (s->clone_sources[i] == parent->root_id) {
110 best_parent = parent;
111 parent = NULL;
112 goto out_found;
116 for (i = 0; i < s->clone_sources_count; i++) {
117 parent2 = get_parent(s, s->clone_sources[i]);
118 if (!parent2)
119 continue;
120 if (parent2->root_id != parent->root_id) {
121 free(parent2->path);
122 free(parent2);
123 parent2 = NULL;
124 continue;
127 free(parent2->path);
128 free(parent2);
129 parent2 = subvol_uuid_search(&s->sus, s->clone_sources[i], NULL,
130 0, NULL, subvol_search_by_root_id);
132 if (!parent2) {
133 ret = -ENOENT;
134 goto out;
136 tmp = parent2->ctransid - parent->ctransid;
137 if (tmp < 0)
138 tmp *= -1;
139 if (tmp < best_diff) {
140 if (best_parent) {
141 free(best_parent->path);
142 free(best_parent);
144 best_parent = parent2;
145 parent2 = NULL;
146 best_diff = tmp;
147 } else {
148 free(parent2->path);
149 free(parent2);
150 parent2 = NULL;
154 if (!best_parent) {
155 ret = -ENOENT;
156 goto out;
159 out_found:
160 *found = best_parent->root_id;
161 ret = 0;
163 out:
164 if (parent) {
165 free(parent->path);
166 free(parent);
168 if (best_parent) {
169 free(best_parent->path);
170 free(best_parent);
172 return ret;
175 static int add_clone_source(struct btrfs_send *s, u64 root_id)
177 void *tmp;
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) {
184 free(tmp);
185 return -ENOMEM;
187 s->clone_sources[s->clone_sources_count++] = root_id;
189 return 0;
192 static int write_buf(int fd, const void *buf, int size)
194 int ret;
195 int pos = 0;
197 while (pos < size) {
198 ret = write(fd, (char*)buf + pos, size - pos);
199 if (ret < 0) {
200 ret = -errno;
201 fprintf(stderr, "ERROR: failed to dump stream. %s\n",
202 strerror(-ret));
203 goto out;
205 if (!ret) {
206 ret = -EIO;
207 fprintf(stderr, "ERROR: failed to dump stream. %s\n",
208 strerror(-ret));
209 goto out;
211 pos += ret;
213 ret = 0;
215 out:
216 return ret;
219 static void *dump_thread(void *arg_)
221 int ret;
222 struct btrfs_send *s = (struct btrfs_send*)arg_;
223 char buf[4096];
224 int readed;
226 while (1) {
227 readed = read(s->send_fd, buf, sizeof(buf));
228 if (readed < 0) {
229 ret = -errno;
230 fprintf(stderr, "ERROR: failed to read stream from "
231 "kernel. %s\n", strerror(-ret));
232 goto out;
234 if (!readed) {
235 ret = 0;
236 goto out;
238 ret = write_buf(s->dump_fd, buf, readed);
239 if (ret < 0)
240 goto out;
243 out:
244 if (ret < 0) {
245 exit(-ret);
248 return ERR_PTR(ret);
251 static int do_send(struct btrfs_send *send, u64 parent_root_id,
252 int is_first_subvol, int is_last_subvol, char *subvol,
253 u64 flags)
255 int ret;
256 pthread_t t_read;
257 struct btrfs_ioctl_send_args io_send;
258 void *t_err = NULL;
259 int subvol_fd = -1;
260 int pipefd[2] = {-1, -1};
262 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
263 if (subvol_fd < 0) {
264 ret = -errno;
265 fprintf(stderr, "ERROR: open %s failed. %s\n", subvol,
266 strerror(-ret));
267 goto out;
270 ret = pipe(pipefd);
271 if (ret < 0) {
272 ret = -errno;
273 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(-ret));
274 goto out;
277 memset(&io_send, 0, sizeof(io_send));
278 io_send.send_fd = pipefd[1];
279 send->send_fd = pipefd[0];
281 if (!ret)
282 ret = pthread_create(&t_read, NULL, dump_thread,
283 send);
284 if (ret) {
285 ret = -ret;
286 fprintf(stderr, "ERROR: thread setup failed: %s\n",
287 strerror(-ret));
288 goto out;
291 io_send.flags = flags;
292 io_send.clone_sources = (__u64*)send->clone_sources;
293 io_send.clone_sources_count = send->clone_sources_count;
294 io_send.parent_root = parent_root_id;
295 if (!is_first_subvol)
296 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
297 if (!is_last_subvol)
298 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
299 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
300 if (ret) {
301 ret = -errno;
302 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
303 strerror(-ret));
304 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
305 fprintf(stderr,
306 "Try upgrading your kernel or don't use -e.\n");
307 goto out;
309 if (g_verbose > 0)
310 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
312 if (g_verbose > 0)
313 fprintf(stderr, "joining genl thread\n");
315 close(pipefd[1]);
316 pipefd[1] = -1;
318 ret = pthread_join(t_read, &t_err);
319 if (ret) {
320 ret = -ret;
321 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
322 strerror(-ret));
323 goto out;
325 if (t_err) {
326 ret = (long int)t_err;
327 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
328 "(%s)\n", (long int)t_err, strerror(-ret));
329 goto out;
332 ret = 0;
334 out:
335 if (subvol_fd != -1)
336 close(subvol_fd);
337 if (pipefd[0] != -1)
338 close(pipefd[0]);
339 if (pipefd[1] != -1)
340 close(pipefd[1]);
341 return ret;
344 char *get_subvol_name(char *mnt, char *full_path)
346 int len = strlen(mnt);
347 if (!len)
348 return full_path;
349 if (mnt[len - 1] != '/')
350 len += 1;
352 return full_path + len;
355 static int init_root_path(struct btrfs_send *s, const char *subvol)
357 int ret = 0;
359 if (s->root_path)
360 goto out;
362 ret = find_mount_root(subvol, &s->root_path);
363 if (ret < 0) {
364 fprintf(stderr,
365 "ERROR: failed to determine mount point for %s: %s\n",
366 subvol, strerror(-ret));
367 ret = -EINVAL;
368 goto out;
370 if (ret > 0) {
371 fprintf(stderr,
372 "ERROR: %s doesn't belong to btrfs mount point\n",
373 subvol);
374 ret = -EINVAL;
375 goto out;
378 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
379 if (s->mnt_fd < 0) {
380 ret = -errno;
381 fprintf(stderr, "ERROR: can't open '%s': %s\n", s->root_path,
382 strerror(-ret));
383 goto out;
386 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
387 if (ret < 0) {
388 fprintf(stderr, "ERROR: failed to initialize subvol search. "
389 "%s\n", strerror(-ret));
390 goto out;
393 out:
394 return ret;
398 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
400 int ret;
401 u64 flags;
402 int fd = -1;
404 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
405 if (fd < 0) {
406 ret = -errno;
407 fprintf(stderr, "ERROR: failed to open %s. %s\n",
408 subvol, strerror(-ret));
409 goto out;
412 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
413 if (ret < 0) {
414 ret = -errno;
415 fprintf(stderr, "ERROR: failed to get flags for subvolume. "
416 "%s\n", strerror(-ret));
417 goto out;
420 if (flags & BTRFS_SUBVOL_RDONLY)
421 ret = 1;
422 else
423 ret = 0;
425 out:
426 if (fd != -1)
427 close(fd);
429 return ret;
432 int cmd_send(int argc, char **argv)
434 char *subvol = NULL;
435 int ret;
436 char outname[PATH_MAX];
437 struct btrfs_send send;
438 u32 i;
439 char *mount_root = NULL;
440 char *snapshot_parent = NULL;
441 u64 root_id = 0;
442 u64 parent_root_id = 0;
443 int full_send = 1;
444 int new_end_cmd_semantic = 0;
445 u64 send_flags = 0;
447 memset(&send, 0, sizeof(send));
448 send.dump_fd = fileno(stdout);
449 outname[0] = 0;
451 while (1) {
452 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
453 static const struct option long_options[] = {
454 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
456 int c = getopt_long(argc, argv, "vec:f:i:p:", long_options, NULL);
458 if (c < 0)
459 break;
461 switch (c) {
462 case 'v':
463 g_verbose++;
464 break;
465 case 'e':
466 new_end_cmd_semantic = 1;
467 break;
468 case 'c':
469 subvol = realpath(optarg, NULL);
470 if (!subvol) {
471 ret = -errno;
472 fprintf(stderr, "ERROR: realpath %s failed. "
473 "%s\n", optarg, strerror(-ret));
474 goto out;
477 ret = init_root_path(&send, subvol);
478 if (ret < 0)
479 goto out;
481 ret = get_root_id(&send, get_subvol_name(send.root_path, subvol),
482 &root_id);
483 if (ret < 0) {
484 fprintf(stderr, "ERROR: could not resolve "
485 "root_id for %s\n", subvol);
486 goto out;
489 ret = is_subvol_ro(&send, subvol);
490 if (ret < 0)
491 goto out;
492 if (!ret) {
493 ret = -EINVAL;
494 fprintf(stderr,
495 "ERROR: cloned subvol %s is not read-only.\n",
496 subvol);
497 goto out;
500 ret = add_clone_source(&send, root_id);
501 if (ret < 0) {
502 fprintf(stderr, "ERROR: not enough memory\n");
503 goto out;
505 subvol_uuid_search_finit(&send.sus);
506 free(subvol);
507 subvol = NULL;
508 if (send.mnt_fd >= 0) {
509 close(send.mnt_fd);
510 send.mnt_fd = -1;
512 free(send.root_path);
513 send.root_path = NULL;
514 full_send = 0;
515 break;
516 case 'f':
517 if (arg_copy_path(outname, optarg, sizeof(outname))) {
518 fprintf(stderr,
519 "ERROR: output file path too long (%zu)\n",
520 strlen(optarg));
521 ret = 1;
522 goto out;
524 break;
525 case 'p':
526 if (snapshot_parent) {
527 fprintf(stderr, "ERROR: you cannot have more than one parent (-p)\n");
528 ret = 1;
529 goto out;
531 snapshot_parent = realpath(optarg, NULL);
532 if (!snapshot_parent) {
533 ret = -errno;
534 fprintf(stderr, "ERROR: realpath %s failed. "
535 "%s\n", optarg, strerror(-ret));
536 goto out;
539 ret = is_subvol_ro(&send, snapshot_parent);
540 if (ret < 0)
541 goto out;
542 if (!ret) {
543 ret = -EINVAL;
544 fprintf(stderr,
545 "ERROR: parent %s is not read-only.\n",
546 snapshot_parent);
547 goto out;
550 full_send = 0;
551 break;
552 case 'i':
553 fprintf(stderr,
554 "ERROR: -i was removed, use -c instead\n");
555 ret = 1;
556 goto out;
557 case GETOPT_VAL_SEND_NO_DATA:
558 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
559 break;
560 case '?':
561 default:
562 fprintf(stderr, "ERROR: send args invalid.\n");
563 ret = 1;
564 goto out;
568 if (check_argc_min(argc - optind, 1))
569 usage(cmd_send_usage);
571 if (outname[0]) {
572 send.dump_fd = creat(outname, 0600);
573 if (send.dump_fd == -1) {
574 ret = -errno;
575 fprintf(stderr, "ERROR: can't create '%s': %s\n",
576 outname, strerror(-ret));
577 goto out;
581 if (isatty(send.dump_fd)) {
582 fprintf(stderr,
583 "ERROR: not dumping send stream into a terminal, "
584 "redirect it into a file\n");
585 ret = 1;
586 goto out;
589 /* use first send subvol to determine mount_root */
590 subvol = argv[optind];
592 subvol = realpath(argv[optind], NULL);
593 if (!subvol) {
594 ret = -errno;
595 fprintf(stderr, "ERROR: unable to resolve %s\n", argv[optind]);
596 goto out;
599 ret = init_root_path(&send, subvol);
600 if (ret < 0)
601 goto out;
603 if (snapshot_parent != NULL) {
604 ret = get_root_id(&send,
605 get_subvol_name(send.root_path, snapshot_parent),
606 &parent_root_id);
607 if (ret < 0) {
608 fprintf(stderr, "ERROR: could not resolve root_id "
609 "for %s\n", snapshot_parent);
610 goto out;
613 ret = add_clone_source(&send, parent_root_id);
614 if (ret < 0) {
615 fprintf(stderr, "ERROR: not enough memory\n");
616 goto out;
620 for (i = optind; i < argc; i++) {
621 free(subvol);
622 subvol = realpath(argv[i], NULL);
623 if (!subvol) {
624 ret = -errno;
625 fprintf(stderr, "ERROR: unable to resolve %s\n", argv[i]);
626 goto out;
629 ret = find_mount_root(subvol, &mount_root);
630 if (ret < 0) {
631 fprintf(stderr, "ERROR: find_mount_root failed on %s: "
632 "%s\n", subvol,
633 strerror(-ret));
634 goto out;
636 if (ret > 0) {
637 fprintf(stderr,
638 "ERROR: %s doesn't belong to btrfs mount point\n",
639 subvol);
640 ret = -EINVAL;
641 goto out;
643 if (strcmp(send.root_path, mount_root) != 0) {
644 ret = -EINVAL;
645 fprintf(stderr, "ERROR: all subvols must be from the "
646 "same fs.\n");
647 goto out;
649 free(mount_root);
651 ret = is_subvol_ro(&send, subvol);
652 if (ret < 0)
653 goto out;
654 if (!ret) {
655 ret = -EINVAL;
656 fprintf(stderr, "ERROR: %s is not read-only.\n",
657 subvol);
658 goto out;
662 if (send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
663 printf("Mode NO_FILE_DATA enabled\n");
665 for (i = optind; i < argc; i++) {
666 int is_first_subvol;
667 int is_last_subvol;
669 free(subvol);
670 subvol = argv[i];
672 fprintf(stderr, "At subvol %s\n", subvol);
674 subvol = realpath(subvol, NULL);
675 if (!subvol) {
676 ret = -errno;
677 fprintf(stderr, "ERROR: realpath %s failed. "
678 "%s\n", argv[i], strerror(-ret));
679 goto out;
682 if (!full_send && !parent_root_id) {
683 ret = find_good_parent(&send, root_id, &parent_root_id);
684 if (ret < 0) {
685 fprintf(stderr, "ERROR: parent determination failed for %lld\n",
686 root_id);
687 goto out;
691 ret = is_subvol_ro(&send, subvol);
692 if (ret < 0)
693 goto out;
694 if (!ret) {
695 ret = -EINVAL;
696 fprintf(stderr, "ERROR: %s is not read-only.\n",
697 subvol);
698 goto out;
701 if (new_end_cmd_semantic) {
702 /* require new kernel */
703 is_first_subvol = (i == optind);
704 is_last_subvol = (i == argc - 1);
705 } else {
706 /* be compatible to old and new kernel */
707 is_first_subvol = 1;
708 is_last_subvol = 1;
710 ret = do_send(&send, parent_root_id, is_first_subvol,
711 is_last_subvol, subvol, send_flags);
712 if (ret < 0)
713 goto out;
715 /* done with this subvol, so add it to the clone sources */
716 ret = add_clone_source(&send, root_id);
717 if (ret < 0) {
718 fprintf(stderr, "ERROR: not enough memory\n");
719 goto out;
722 parent_root_id = 0;
723 full_send = 0;
726 ret = 0;
728 out:
729 free(subvol);
730 free(snapshot_parent);
731 free(send.clone_sources);
732 if (send.mnt_fd >= 0)
733 close(send.mnt_fd);
734 free(send.root_path);
735 subvol_uuid_search_finit(&send.sus);
736 return !!ret;
739 const char * const cmd_send_usage[] = {
740 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
741 "Send the subvolume(s) to stdout.",
742 "Sends the subvolume(s) specified by <subvol> to stdout.",
743 "By default, this will send the whole subvolume. To do an incremental",
744 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
745 "any additional local snapshots, use '-c <clone-src>' (multiple times",
746 "where applicable). You must not specify clone sources unless you",
747 "guarantee that these snapshots are exactly in the same state on both",
748 "sides, the sender and the receiver. It is allowed to omit the",
749 "'-p <parent>' option when '-c <clone-src>' options are given, in",
750 "which case 'btrfs send' will determine a suitable parent among the",
751 "clone sources itself.",
752 "\n",
753 "-v Enable verbose debug output. Each occurrence of",
754 " this option increases the verbose level more.",
755 "-e If sending multiple subvols at once, use the new",
756 " format and omit the end-cmd between the subvols.",
757 "-p <parent> Send an incremental stream from <parent> to",
758 " <subvol>.",
759 "-c <clone-src> Use this snapshot as a clone source for an ",
760 " incremental send (multiple allowed)",
761 "-f <outfile> Output is normally written to stdout. To write to",
762 " a file, use this option. An alternative would be to",
763 " use pipes.",
764 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
765 " does not contain any file data and thus cannot be used",
766 " to transfer changes. This mode is faster and useful to",
767 " show the differences in metadata.",
768 NULL