btrfs-progs: convert: move create_image
[btrfs-progs-unstable/devel.git] / cmds-send.c
blob74d01287bcb93afb8c44d4d141dcbcf54a9d4212
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"
48 * Default is 1 for historical reasons, changing may break scripts that expect
49 * the 'At subvol' message.
51 static int g_verbose = 1;
53 struct btrfs_send {
54 int send_fd;
55 int dump_fd;
56 int mnt_fd;
58 u64 *clone_sources;
59 u64 clone_sources_count;
61 char *root_path;
62 struct subvol_uuid_search sus;
65 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
67 struct subvol_info *si;
69 si = subvol_uuid_search(&s->sus, 0, NULL, 0, path,
70 subvol_search_by_path);
71 if (!si)
72 return -ENOENT;
73 *root_id = si->root_id;
74 free(si->path);
75 free(si);
76 return 0;
79 static struct subvol_info *get_parent(struct btrfs_send *s, u64 root_id)
81 struct subvol_info *si_tmp;
82 struct subvol_info *si;
84 si_tmp = subvol_uuid_search(&s->sus, root_id, NULL, 0, NULL,
85 subvol_search_by_root_id);
86 if (!si_tmp)
87 return NULL;
89 si = subvol_uuid_search(&s->sus, 0, si_tmp->parent_uuid, 0, NULL,
90 subvol_search_by_uuid);
91 free(si_tmp->path);
92 free(si_tmp);
93 return si;
96 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
98 int ret;
99 struct subvol_info *parent = NULL;
100 struct subvol_info *parent2 = NULL;
101 struct subvol_info *best_parent = NULL;
102 __s64 tmp;
103 u64 best_diff = (u64)-1;
104 int i;
106 parent = get_parent(s, root_id);
107 if (!parent) {
108 ret = -ENOENT;
109 goto out;
112 for (i = 0; i < s->clone_sources_count; i++) {
113 if (s->clone_sources[i] == parent->root_id) {
114 best_parent = parent;
115 parent = NULL;
116 goto out_found;
120 for (i = 0; i < s->clone_sources_count; i++) {
121 parent2 = get_parent(s, s->clone_sources[i]);
122 if (!parent2)
123 continue;
124 if (parent2->root_id != parent->root_id) {
125 free(parent2->path);
126 free(parent2);
127 parent2 = NULL;
128 continue;
131 free(parent2->path);
132 free(parent2);
133 parent2 = subvol_uuid_search(&s->sus, s->clone_sources[i], NULL,
134 0, NULL, subvol_search_by_root_id);
136 if (!parent2) {
137 ret = -ENOENT;
138 goto out;
140 tmp = parent2->ctransid - parent->ctransid;
141 if (tmp < 0)
142 tmp *= -1;
143 if (tmp < best_diff) {
144 if (best_parent) {
145 free(best_parent->path);
146 free(best_parent);
148 best_parent = parent2;
149 parent2 = NULL;
150 best_diff = tmp;
151 } else {
152 free(parent2->path);
153 free(parent2);
154 parent2 = NULL;
158 if (!best_parent) {
159 ret = -ENOENT;
160 goto out;
163 out_found:
164 *found = best_parent->root_id;
165 ret = 0;
167 out:
168 if (parent) {
169 free(parent->path);
170 free(parent);
172 if (best_parent) {
173 free(best_parent->path);
174 free(best_parent);
176 return ret;
179 static int add_clone_source(struct btrfs_send *s, u64 root_id)
181 void *tmp;
183 tmp = s->clone_sources;
184 s->clone_sources = realloc(s->clone_sources,
185 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
187 if (!s->clone_sources) {
188 free(tmp);
189 return -ENOMEM;
191 s->clone_sources[s->clone_sources_count++] = root_id;
193 return 0;
196 static int write_buf(int fd, const void *buf, int size)
198 int ret;
199 int pos = 0;
201 while (pos < size) {
202 ret = write(fd, (char*)buf + pos, size - pos);
203 if (ret < 0) {
204 ret = -errno;
205 error("failed to dump stream: %s", strerror(-ret));
206 goto out;
208 if (!ret) {
209 ret = -EIO;
210 error("failed to dump stream: %s", strerror(-ret));
211 goto out;
213 pos += ret;
215 ret = 0;
217 out:
218 return ret;
221 static void *dump_thread(void *arg_)
223 int ret;
224 struct btrfs_send *s = (struct btrfs_send*)arg_;
225 char buf[4096];
226 int readed;
228 while (1) {
229 readed = read(s->send_fd, buf, sizeof(buf));
230 if (readed < 0) {
231 ret = -errno;
232 error("failed to read stream from kernel: %s\n",
233 strerror(-ret));
234 goto out;
236 if (!readed) {
237 ret = 0;
238 goto out;
240 ret = write_buf(s->dump_fd, buf, readed);
241 if (ret < 0)
242 goto out;
245 out:
246 if (ret < 0) {
247 exit(-ret);
250 return ERR_PTR(ret);
253 static int do_send(struct btrfs_send *send, u64 parent_root_id,
254 int is_first_subvol, int is_last_subvol, char *subvol,
255 u64 flags)
257 int ret;
258 pthread_t t_read;
259 struct btrfs_ioctl_send_args io_send;
260 void *t_err = NULL;
261 int subvol_fd = -1;
262 int pipefd[2] = {-1, -1};
264 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
265 if (subvol_fd < 0) {
266 ret = -errno;
267 error("cannot open %s: %s", subvol, strerror(-ret));
268 goto out;
271 ret = pipe(pipefd);
272 if (ret < 0) {
273 ret = -errno;
274 error("pipe failed: %s", strerror(-ret));
275 goto out;
278 memset(&io_send, 0, sizeof(io_send));
279 io_send.send_fd = pipefd[1];
280 send->send_fd = pipefd[0];
282 if (!ret)
283 ret = pthread_create(&t_read, NULL, dump_thread,
284 send);
285 if (ret) {
286 ret = -ret;
287 error("thread setup failed: %s", 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 < 0) {
301 ret = -errno;
302 error("send ioctl failed with %d: %s", ret, strerror(-ret));
303 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
304 fprintf(stderr,
305 "Try upgrading your kernel or don't use -e.\n");
306 goto out;
308 if (g_verbose > 1)
309 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
311 if (g_verbose > 1)
312 fprintf(stderr, "joining genl thread\n");
314 close(pipefd[1]);
315 pipefd[1] = -1;
317 ret = pthread_join(t_read, &t_err);
318 if (ret) {
319 ret = -ret;
320 error("pthread_join failed: %s", strerror(-ret));
321 goto out;
323 if (t_err) {
324 ret = (long int)t_err;
325 error("failed to process send stream, ret=%ld (%s)",
326 (long int)t_err, strerror(-ret));
327 goto out;
330 ret = 0;
332 out:
333 if (subvol_fd != -1)
334 close(subvol_fd);
335 if (pipefd[0] != -1)
336 close(pipefd[0]);
337 if (pipefd[1] != -1)
338 close(pipefd[1]);
339 return ret;
342 static int init_root_path(struct btrfs_send *s, const char *subvol)
344 int ret = 0;
346 if (s->root_path)
347 goto out;
349 ret = find_mount_root(subvol, &s->root_path);
350 if (ret < 0) {
351 error("failed to determine mount point for %s: %s",
352 subvol, strerror(-ret));
353 ret = -EINVAL;
354 goto out;
356 if (ret > 0) {
357 error("%s doesn't belong to btrfs mount point", subvol);
358 ret = -EINVAL;
359 goto out;
362 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
363 if (s->mnt_fd < 0) {
364 ret = -errno;
365 error("cannot open '%s': %s", s->root_path, strerror(-ret));
366 goto out;
369 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
370 if (ret < 0) {
371 error("failed to initialize subvol search: %s",
372 strerror(-ret));
373 goto out;
376 out:
377 return ret;
381 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
383 int ret;
384 u64 flags;
385 int fd = -1;
387 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
388 if (fd < 0) {
389 ret = -errno;
390 error("cannot open %s: %s", subvol, strerror(-ret));
391 goto out;
394 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
395 if (ret < 0) {
396 ret = -errno;
397 error("failed to get flags for subvolume %s: %s",
398 subvol, strerror(-ret));
399 goto out;
402 if (flags & BTRFS_SUBVOL_RDONLY)
403 ret = 1;
404 else
405 ret = 0;
407 out:
408 if (fd != -1)
409 close(fd);
411 return ret;
414 int cmd_send(int argc, char **argv)
416 char *subvol = NULL;
417 int ret;
418 char outname[PATH_MAX];
419 struct btrfs_send send;
420 u32 i;
421 char *mount_root = NULL;
422 char *snapshot_parent = NULL;
423 u64 root_id = 0;
424 u64 parent_root_id = 0;
425 int full_send = 1;
426 int new_end_cmd_semantic = 0;
427 u64 send_flags = 0;
429 memset(&send, 0, sizeof(send));
430 send.dump_fd = fileno(stdout);
431 outname[0] = 0;
433 while (1) {
434 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
435 static const struct option long_options[] = {
436 { "verbose", no_argument, NULL, 'v' },
437 { "quiet", no_argument, NULL, 'q' },
438 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
440 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
442 if (c < 0)
443 break;
445 switch (c) {
446 case 'v':
447 g_verbose++;
448 break;
449 case 'q':
450 g_verbose = 0;
451 break;
452 case 'e':
453 new_end_cmd_semantic = 1;
454 break;
455 case 'c':
456 subvol = realpath(optarg, NULL);
457 if (!subvol) {
458 ret = -errno;
459 error("realpath %s failed: %s\n", optarg, strerror(-ret));
460 goto out;
463 ret = init_root_path(&send, subvol);
464 if (ret < 0)
465 goto out;
467 ret = get_root_id(&send,
468 subvol_strip_mountpoint(send.root_path, subvol),
469 &root_id);
470 if (ret < 0) {
471 error("cannot resolve rootid for %s", subvol);
472 goto out;
475 ret = is_subvol_ro(&send, subvol);
476 if (ret < 0)
477 goto out;
478 if (!ret) {
479 ret = -EINVAL;
480 error("cloned subvolume %s is not read-only", subvol);
481 goto out;
484 ret = add_clone_source(&send, root_id);
485 if (ret < 0) {
486 error("cannot add clone source: %s", strerror(-ret));
487 goto out;
489 subvol_uuid_search_finit(&send.sus);
490 free(subvol);
491 subvol = NULL;
492 if (send.mnt_fd >= 0) {
493 close(send.mnt_fd);
494 send.mnt_fd = -1;
496 free(send.root_path);
497 send.root_path = NULL;
498 full_send = 0;
499 break;
500 case 'f':
501 if (arg_copy_path(outname, optarg, sizeof(outname))) {
502 error("output file path too long (%zu)", strlen(optarg));
503 ret = 1;
504 goto out;
506 break;
507 case 'p':
508 if (snapshot_parent) {
509 error("you cannot have more than one parent (-p)");
510 ret = 1;
511 goto out;
513 snapshot_parent = realpath(optarg, NULL);
514 if (!snapshot_parent) {
515 ret = -errno;
516 error("realpath %s failed: %s", optarg, strerror(-ret));
517 goto out;
520 ret = is_subvol_ro(&send, snapshot_parent);
521 if (ret < 0)
522 goto out;
523 if (!ret) {
524 ret = -EINVAL;
525 error("parent subvolume %s is not read-only",
526 snapshot_parent);
527 goto out;
530 full_send = 0;
531 break;
532 case 'i':
533 error("option -i was removed, use -c instead");
534 ret = 1;
535 goto out;
536 case GETOPT_VAL_SEND_NO_DATA:
537 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
538 break;
539 case '?':
540 default:
541 error("send arguments invalid");
542 ret = 1;
543 goto out;
547 if (check_argc_min(argc - optind, 1))
548 usage(cmd_send_usage);
550 if (outname[0]) {
551 send.dump_fd = creat(outname, 0600);
552 if (send.dump_fd == -1) {
553 ret = -errno;
554 error("cannot create '%s': %s", outname, strerror(-ret));
555 goto out;
559 if (isatty(send.dump_fd)) {
560 error(
561 "not dumping send stream into a terminal, redirect it into a file");
562 ret = 1;
563 goto out;
566 /* use first send subvol to determine mount_root */
567 subvol = argv[optind];
569 subvol = realpath(argv[optind], NULL);
570 if (!subvol) {
571 ret = -errno;
572 error("unable to resolve %s", argv[optind]);
573 goto out;
576 ret = init_root_path(&send, subvol);
577 if (ret < 0)
578 goto out;
580 if (snapshot_parent != NULL) {
581 ret = get_root_id(&send,
582 subvol_strip_mountpoint(send.root_path, snapshot_parent),
583 &parent_root_id);
584 if (ret < 0) {
585 error("could not resolve rootid for %s", snapshot_parent);
586 goto out;
589 ret = add_clone_source(&send, parent_root_id);
590 if (ret < 0) {
591 error("cannot add clone source: %s", strerror(-ret));
592 goto out;
596 for (i = optind; i < argc; i++) {
597 free(subvol);
598 subvol = realpath(argv[i], NULL);
599 if (!subvol) {
600 ret = -errno;
601 error("unable to resolve %s", argv[i]);
602 goto out;
605 ret = find_mount_root(subvol, &mount_root);
606 if (ret < 0) {
607 error("find_mount_root failed on %s: %s", subvol,
608 strerror(-ret));
609 goto out;
611 if (ret > 0) {
612 error("%s does not belong to btrfs mount point",
613 subvol);
614 ret = -EINVAL;
615 goto out;
617 if (strcmp(send.root_path, mount_root) != 0) {
618 ret = -EINVAL;
619 error("all subvolumes must be from the same filesystem");
620 goto out;
622 free(mount_root);
624 ret = is_subvol_ro(&send, subvol);
625 if (ret < 0)
626 goto out;
627 if (!ret) {
628 ret = -EINVAL;
629 error("subvolume %s is not read-only", subvol);
630 goto out;
634 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
635 if (g_verbose > 1)
636 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
638 for (i = optind; i < argc; i++) {
639 int is_first_subvol;
640 int is_last_subvol;
642 free(subvol);
643 subvol = argv[i];
645 if (g_verbose > 0)
646 fprintf(stderr, "At subvol %s\n", subvol);
648 subvol = realpath(subvol, NULL);
649 if (!subvol) {
650 ret = -errno;
651 error("realpath %s failed: %s", argv[i], strerror(-ret));
652 goto out;
655 if (!full_send && !parent_root_id) {
656 ret = find_good_parent(&send, root_id, &parent_root_id);
657 if (ret < 0) {
658 error("parent determination failed for %lld",
659 root_id);
660 goto out;
664 ret = is_subvol_ro(&send, subvol);
665 if (ret < 0)
666 goto out;
667 if (!ret) {
668 ret = -EINVAL;
669 error("subvolume %s is not read-only", subvol);
670 goto out;
673 if (new_end_cmd_semantic) {
674 /* require new kernel */
675 is_first_subvol = (i == optind);
676 is_last_subvol = (i == argc - 1);
677 } else {
678 /* be compatible to old and new kernel */
679 is_first_subvol = 1;
680 is_last_subvol = 1;
682 ret = do_send(&send, parent_root_id, is_first_subvol,
683 is_last_subvol, subvol, send_flags);
684 if (ret < 0)
685 goto out;
687 if (!full_send) {
688 /* done with this subvol, so add it to the clone sources */
689 ret = add_clone_source(&send, root_id);
690 if (ret < 0) {
691 error("cannot add clone source: %s", strerror(-ret));
692 goto out;
696 parent_root_id = 0;
699 ret = 0;
701 out:
702 free(subvol);
703 free(snapshot_parent);
704 free(send.clone_sources);
705 if (send.mnt_fd >= 0)
706 close(send.mnt_fd);
707 free(send.root_path);
708 subvol_uuid_search_finit(&send.sus);
709 return !!ret;
712 const char * const cmd_send_usage[] = {
713 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
714 "Send the subvolume(s) to stdout.",
715 "Sends the subvolume(s) specified by <subvol> to stdout.",
716 "<subvol> should be read-only here.",
717 "By default, this will send the whole subvolume. To do an incremental",
718 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
719 "any additional local snapshots, use '-c <clone-src>' (multiple times",
720 "where applicable). You must not specify clone sources unless you",
721 "guarantee that these snapshots are exactly in the same state on both",
722 "sides, the sender and the receiver. It is allowed to omit the",
723 "'-p <parent>' option when '-c <clone-src>' options are given, in",
724 "which case 'btrfs send' will determine a suitable parent among the",
725 "clone sources itself.",
726 "\n",
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",
730 " <subvol>.",
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",
735 " use pipes.",
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.",
740 "-v|--verbose enable verbose output to stderr, each occurrence of",
741 " this option increases verbosity",
742 "-q|--quiet suppress all messages, except errors",
743 NULL