btrfs-progs: Convert man page for btrfs-send.
[btrfs-progs-unstable/devel.git] / cmds-send.c
blobdcb6607688c5085834c79ef74b58ae00742d7f48
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.
19 #define _GNU_SOURCE
21 #include "kerncompat.h"
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <dirent.h>
26 #include <fcntl.h>
27 #include <pthread.h>
28 #include <math.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <libgen.h>
33 #include <mntent.h>
34 #include <assert.h>
36 #include <uuid/uuid.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 assert(parent2);
133 tmp = parent2->ctransid - parent->ctransid;
134 if (tmp < 0)
135 tmp *= -1;
136 if (tmp < best_diff) {
137 if (best_parent) {
138 free(best_parent->path);
139 free(best_parent);
141 best_parent = parent2;
142 parent2 = NULL;
143 best_diff = tmp;
144 } else {
145 free(parent2->path);
146 free(parent2);
147 parent2 = NULL;
151 if (!best_parent) {
152 ret = -ENOENT;
153 goto out;
156 out_found:
157 *found = best_parent->root_id;
158 ret = 0;
160 out:
161 if (parent) {
162 free(parent->path);
163 free(parent);
165 if (best_parent) {
166 free(best_parent->path);
167 free(best_parent);
169 return ret;
172 static void add_clone_source(struct btrfs_send *s, u64 root_id)
174 s->clone_sources = realloc(s->clone_sources,
175 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
176 s->clone_sources[s->clone_sources_count++] = root_id;
179 static int write_buf(int fd, const void *buf, int size)
181 int ret;
182 int pos = 0;
184 while (pos < size) {
185 ret = write(fd, (char*)buf + pos, size - pos);
186 if (ret < 0) {
187 ret = -errno;
188 fprintf(stderr, "ERROR: failed to dump stream. %s",
189 strerror(-ret));
190 goto out;
192 if (!ret) {
193 ret = -EIO;
194 fprintf(stderr, "ERROR: failed to dump stream. %s",
195 strerror(-ret));
196 goto out;
198 pos += ret;
200 ret = 0;
202 out:
203 return ret;
206 static void *dump_thread(void *arg_)
208 int ret;
209 struct btrfs_send *s = (struct btrfs_send*)arg_;
210 char buf[4096];
211 int readed;
213 while (1) {
214 readed = read(s->send_fd, buf, sizeof(buf));
215 if (readed < 0) {
216 ret = -errno;
217 fprintf(stderr, "ERROR: failed to read stream from "
218 "kernel. %s\n", strerror(-ret));
219 goto out;
221 if (!readed) {
222 ret = 0;
223 goto out;
225 ret = write_buf(s->dump_fd, buf, readed);
226 if (ret < 0)
227 goto out;
230 out:
231 if (ret < 0) {
232 exit(-ret);
235 return ERR_PTR(ret);
238 static int do_send(struct btrfs_send *send, u64 parent_root_id,
239 int is_first_subvol, int is_last_subvol, char *subvol)
241 int ret;
242 pthread_t t_read;
243 pthread_attr_t t_attr;
244 struct btrfs_ioctl_send_args io_send;
245 void *t_err = NULL;
246 int subvol_fd = -1;
247 int pipefd[2] = {-1, -1};
249 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
250 if (subvol_fd < 0) {
251 ret = -errno;
252 fprintf(stderr, "ERROR: open %s failed. %s\n", subvol,
253 strerror(-ret));
254 goto out;
257 ret = pthread_attr_init(&t_attr);
259 ret = pipe(pipefd);
260 if (ret < 0) {
261 ret = -errno;
262 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(-ret));
263 goto out;
266 memset(&io_send, 0, sizeof(io_send));
267 io_send.send_fd = pipefd[1];
268 send->send_fd = pipefd[0];
270 if (!ret)
271 ret = pthread_create(&t_read, &t_attr, dump_thread,
272 send);
273 if (ret) {
274 ret = -ret;
275 fprintf(stderr, "ERROR: thread setup failed: %s\n",
276 strerror(-ret));
277 goto out;
280 io_send.clone_sources = (__u64*)send->clone_sources;
281 io_send.clone_sources_count = send->clone_sources_count;
282 io_send.parent_root = parent_root_id;
283 if (!is_first_subvol)
284 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
285 if (!is_last_subvol)
286 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
287 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
288 if (ret) {
289 ret = -errno;
290 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
291 strerror(-ret));
292 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
293 fprintf(stderr,
294 "Try upgrading your kernel or don't use -e.\n");
295 goto out;
297 if (g_verbose > 0)
298 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
300 if (g_verbose > 0)
301 fprintf(stderr, "joining genl thread\n");
303 close(pipefd[1]);
304 pipefd[1] = -1;
306 ret = pthread_join(t_read, &t_err);
307 if (ret) {
308 ret = -ret;
309 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
310 strerror(-ret));
311 goto out;
313 if (t_err) {
314 ret = (long int)t_err;
315 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
316 "(%s)\n", (long int)t_err, strerror(-ret));
317 goto out;
320 pthread_attr_destroy(&t_attr);
322 ret = 0;
324 out:
325 if (subvol_fd != -1)
326 close(subvol_fd);
327 if (pipefd[0] != -1)
328 close(pipefd[0]);
329 if (pipefd[1] != -1)
330 close(pipefd[1]);
331 return ret;
334 char *get_subvol_name(char *mnt, char *full_path)
336 int len = strlen(mnt);
337 if (!len)
338 return full_path;
339 if (mnt[len - 1] != '/')
340 len += 1;
342 return full_path + len;
345 static int init_root_path(struct btrfs_send *s, const char *subvol)
347 int ret = 0;
349 if (s->root_path)
350 goto out;
352 ret = find_mount_root(subvol, &s->root_path);
353 if (ret < 0) {
354 ret = -EINVAL;
355 fprintf(stderr, "ERROR: failed to determine mount point "
356 "for %s\n", subvol);
357 goto out;
360 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
361 if (s->mnt_fd < 0) {
362 ret = -errno;
363 fprintf(stderr, "ERROR: can't open '%s': %s\n", s->root_path,
364 strerror(-ret));
365 goto out;
368 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
369 if (ret < 0) {
370 fprintf(stderr, "ERROR: failed to initialize subvol search. "
371 "%s\n", strerror(-ret));
372 goto out;
375 out:
376 return ret;
380 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
382 int ret;
383 u64 flags;
384 int fd = -1;
386 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
387 if (fd < 0) {
388 ret = -errno;
389 fprintf(stderr, "ERROR: failed to open %s. %s\n",
390 subvol, strerror(-ret));
391 goto out;
394 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
395 if (ret < 0) {
396 ret = -errno;
397 fprintf(stderr, "ERROR: failed to get flags for subvolume. "
398 "%s\n", 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 c;
418 int ret;
419 char *outname = NULL;
420 struct btrfs_send send;
421 u32 i;
422 char *mount_root = NULL;
423 char *snapshot_parent = NULL;
424 u64 root_id;
425 u64 parent_root_id = 0;
426 int full_send = 1;
427 int new_end_cmd_semantic = 0;
429 memset(&send, 0, sizeof(send));
430 send.dump_fd = fileno(stdout);
432 while ((c = getopt(argc, argv, "vec:f:i:p:")) != -1) {
433 switch (c) {
434 case 'v':
435 g_verbose++;
436 break;
437 case 'e':
438 new_end_cmd_semantic = 1;
439 break;
440 case 'c':
441 subvol = realpath(optarg, NULL);
442 if (!subvol) {
443 ret = -errno;
444 fprintf(stderr, "ERROR: realpath %s failed. "
445 "%s\n", optarg, strerror(-ret));
446 goto out;
449 ret = init_root_path(&send, subvol);
450 if (ret < 0)
451 goto out;
453 ret = get_root_id(&send, get_subvol_name(send.root_path, subvol),
454 &root_id);
455 if (ret < 0) {
456 fprintf(stderr, "ERROR: could not resolve "
457 "root_id for %s\n", subvol);
458 goto out;
461 ret = is_subvol_ro(&send, subvol);
462 if (ret < 0)
463 goto out;
464 if (!ret) {
465 ret = -EINVAL;
466 fprintf(stderr,
467 "ERROR: cloned subvol %s is not read-only.\n",
468 subvol);
469 goto out;
472 add_clone_source(&send, root_id);
473 subvol_uuid_search_finit(&send.sus);
474 free(subvol);
475 subvol = NULL;
476 if (send.mnt_fd >= 0) {
477 close(send.mnt_fd);
478 send.mnt_fd = -1;
480 free(send.root_path);
481 send.root_path = NULL;
482 full_send = 0;
483 break;
484 case 'f':
485 outname = optarg;
486 break;
487 case 'p':
488 if (snapshot_parent) {
489 fprintf(stderr, "ERROR: you cannot have more than one parent (-p)\n");
490 ret = 1;
491 goto out;
493 snapshot_parent = realpath(optarg, NULL);
494 if (!snapshot_parent) {
495 ret = -errno;
496 fprintf(stderr, "ERROR: realpath %s failed. "
497 "%s\n", optarg, strerror(-ret));
498 goto out;
501 ret = is_subvol_ro(&send, snapshot_parent);
502 if (ret < 0)
503 goto out;
504 if (!ret) {
505 ret = -EINVAL;
506 fprintf(stderr,
507 "ERROR: parent %s is not read-only.\n",
508 snapshot_parent);
509 goto out;
512 full_send = 0;
513 break;
514 case 'i':
515 fprintf(stderr,
516 "ERROR: -i was removed, use -c instead\n");
517 ret = 1;
518 goto out;
519 case '?':
520 default:
521 fprintf(stderr, "ERROR: send args invalid.\n");
522 ret = 1;
523 goto out;
527 if (optind == argc)
528 usage(cmd_send_usage);
530 if (outname != NULL) {
531 send.dump_fd = creat(outname, 0600);
532 if (send.dump_fd == -1) {
533 ret = -errno;
534 fprintf(stderr, "ERROR: can't create '%s': %s\n",
535 outname, strerror(-ret));
536 goto out;
540 if (isatty(send.dump_fd)) {
541 fprintf(stderr,
542 "ERROR: not dumping send stream into a terminal, "
543 "redirect it into a file\n");
544 ret = 1;
545 goto out;
548 /* use first send subvol to determine mount_root */
549 subvol = argv[optind];
551 subvol = realpath(argv[optind], NULL);
552 if (!subvol) {
553 ret = -errno;
554 fprintf(stderr, "ERROR: unable to resolve %s\n", argv[optind]);
555 goto out;
558 ret = init_root_path(&send, subvol);
559 if (ret < 0)
560 goto out;
562 if (snapshot_parent != NULL) {
563 ret = get_root_id(&send,
564 get_subvol_name(send.root_path, snapshot_parent),
565 &parent_root_id);
566 if (ret < 0) {
567 fprintf(stderr, "ERROR: could not resolve root_id "
568 "for %s\n", snapshot_parent);
569 goto out;
572 add_clone_source(&send, parent_root_id);
575 for (i = optind; i < argc; i++) {
576 free(subvol);
577 subvol = realpath(argv[i], NULL);
578 if (!subvol) {
579 ret = -errno;
580 fprintf(stderr, "ERROR: unable to resolve %s\n", argv[i]);
581 goto out;
584 ret = find_mount_root(subvol, &mount_root);
585 if (ret < 0) {
586 fprintf(stderr, "ERROR: find_mount_root failed on %s: "
587 "%s\n", subvol,
588 strerror(-ret));
589 goto out;
591 if (strcmp(send.root_path, mount_root) != 0) {
592 ret = -EINVAL;
593 fprintf(stderr, "ERROR: all subvols must be from the "
594 "same fs.\n");
595 goto out;
597 free(mount_root);
599 ret = is_subvol_ro(&send, subvol);
600 if (ret < 0)
601 goto out;
602 if (!ret) {
603 ret = -EINVAL;
604 fprintf(stderr, "ERROR: %s is not read-only.\n",
605 subvol);
606 goto out;
610 for (i = optind; i < argc; i++) {
611 int is_first_subvol;
612 int is_last_subvol;
614 free(subvol);
615 subvol = argv[i];
617 fprintf(stderr, "At subvol %s\n", subvol);
619 subvol = realpath(subvol, NULL);
620 if (!subvol) {
621 ret = -errno;
622 fprintf(stderr, "ERROR: realpath %s failed. "
623 "%s\n", argv[i], strerror(-ret));
624 goto out;
627 if (!full_send && !parent_root_id) {
628 ret = find_good_parent(&send, root_id, &parent_root_id);
629 if (ret < 0) {
630 fprintf(stderr, "ERROR: parent determination failed for %lld\n",
631 root_id);
632 goto out;
636 ret = is_subvol_ro(&send, subvol);
637 if (ret < 0)
638 goto out;
639 if (!ret) {
640 ret = -EINVAL;
641 fprintf(stderr, "ERROR: %s is not read-only.\n",
642 subvol);
643 goto out;
646 if (new_end_cmd_semantic) {
647 /* require new kernel */
648 is_first_subvol = (i == optind);
649 is_last_subvol = (i == argc - 1);
650 } else {
651 /* be compatible to old and new kernel */
652 is_first_subvol = 1;
653 is_last_subvol = 1;
655 ret = do_send(&send, parent_root_id, is_first_subvol,
656 is_last_subvol, subvol);
657 if (ret < 0)
658 goto out;
660 /* done with this subvol, so add it to the clone sources */
661 add_clone_source(&send, root_id);
663 parent_root_id = 0;
664 full_send = 0;
667 ret = 0;
669 out:
670 free(subvol);
671 free(snapshot_parent);
672 free(send.clone_sources);
673 if (send.mnt_fd >= 0)
674 close(send.mnt_fd);
675 free(send.root_path);
676 subvol_uuid_search_finit(&send.sus);
677 return !!ret;
680 const char * const cmd_send_usage[] = {
681 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
682 "Send the subvolume(s) to stdout.",
683 "Sends the subvolume(s) specified by <subvol> to stdout.",
684 "By default, this will send the whole subvolume. To do an incremental",
685 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
686 "any additional local snapshots, use '-c <clone-src>' (multiple times",
687 "where applicable). You must not specify clone sources unless you",
688 "guarantee that these snapshots are exactly in the same state on both",
689 "sides, the sender and the receiver. It is allowed to omit the",
690 "'-p <parent>' option when '-c <clone-src>' options are given, in",
691 "which case 'btrfs send' will determine a suitable parent among the",
692 "clone sources itself.",
693 "\n",
694 "-v Enable verbose debug output. Each occurrence of",
695 " this option increases the verbose level more.",
696 "-e If sending multiple subvols at once, use the new",
697 " format and omit the end-cmd between the subvols.",
698 "-p <parent> Send an incremental stream from <parent> to",
699 " <subvol>.",
700 "-c <clone-src> Use this snapshot as a clone source for an ",
701 " incremental send (multiple allowed)",
702 "-f <outfile> Output is normally written to stdout. To write to",
703 " a file, use this option. An alternative would be to",
704 " use pipes.",
705 NULL