btrfs-progs: fi du: add long options for units
[btrfs-progs-unstable/devel.git] / cmds-send.c
blob3e34d75bb8344da76a4e4fda4cf972298fd41321
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 error("failed to dump stream: %s", strerror(-ret));
202 goto out;
204 if (!ret) {
205 ret = -EIO;
206 error("failed to dump stream: %s", strerror(-ret));
207 goto out;
209 pos += ret;
211 ret = 0;
213 out:
214 return ret;
217 static void *dump_thread(void *arg_)
219 int ret;
220 struct btrfs_send *s = (struct btrfs_send*)arg_;
221 char buf[4096];
222 int readed;
224 while (1) {
225 readed = read(s->send_fd, buf, sizeof(buf));
226 if (readed < 0) {
227 ret = -errno;
228 error("failed to read stream from kernel: %s\n",
229 strerror(-ret));
230 goto out;
232 if (!readed) {
233 ret = 0;
234 goto out;
236 ret = write_buf(s->dump_fd, buf, readed);
237 if (ret < 0)
238 goto out;
241 out:
242 if (ret < 0) {
243 exit(-ret);
246 return ERR_PTR(ret);
249 static int do_send(struct btrfs_send *send, u64 parent_root_id,
250 int is_first_subvol, int is_last_subvol, char *subvol,
251 u64 flags)
253 int ret;
254 pthread_t t_read;
255 struct btrfs_ioctl_send_args io_send;
256 void *t_err = NULL;
257 int subvol_fd = -1;
258 int pipefd[2] = {-1, -1};
260 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
261 if (subvol_fd < 0) {
262 ret = -errno;
263 error("cannot open %s: %s", subvol, strerror(-ret));
264 goto out;
267 ret = pipe(pipefd);
268 if (ret < 0) {
269 ret = -errno;
270 error("pipe failed: %s", strerror(-ret));
271 goto out;
274 memset(&io_send, 0, sizeof(io_send));
275 io_send.send_fd = pipefd[1];
276 send->send_fd = pipefd[0];
278 if (!ret)
279 ret = pthread_create(&t_read, NULL, dump_thread,
280 send);
281 if (ret) {
282 ret = -ret;
283 error("thread setup failed: %s", strerror(-ret));
284 goto out;
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;
293 if (!is_last_subvol)
294 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
295 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
296 if (ret < 0) {
297 ret = -errno;
298 error("send ioctl failed with %d: %s", ret, strerror(-ret));
299 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
300 fprintf(stderr,
301 "Try upgrading your kernel or don't use -e.\n");
302 goto out;
304 if (g_verbose > 0)
305 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
307 if (g_verbose > 0)
308 fprintf(stderr, "joining genl thread\n");
310 close(pipefd[1]);
311 pipefd[1] = -1;
313 ret = pthread_join(t_read, &t_err);
314 if (ret) {
315 ret = -ret;
316 error("pthread_join failed: %s", strerror(-ret));
317 goto out;
319 if (t_err) {
320 ret = (long int)t_err;
321 error("failed to process send stream, ret=%ld (%s)",
322 (long int)t_err, strerror(-ret));
323 goto out;
326 ret = 0;
328 out:
329 if (subvol_fd != -1)
330 close(subvol_fd);
331 if (pipefd[0] != -1)
332 close(pipefd[0]);
333 if (pipefd[1] != -1)
334 close(pipefd[1]);
335 return ret;
338 char *get_subvol_name(char *mnt, char *full_path)
340 int len = strlen(mnt);
341 if (!len)
342 return full_path;
343 if (mnt[len - 1] != '/')
344 len += 1;
346 return full_path + len;
349 static int init_root_path(struct btrfs_send *s, const char *subvol)
351 int ret = 0;
353 if (s->root_path)
354 goto out;
356 ret = find_mount_root(subvol, &s->root_path);
357 if (ret < 0) {
358 error("failed to determine mount point for %s: %s",
359 subvol, strerror(-ret));
360 ret = -EINVAL;
361 goto out;
363 if (ret > 0) {
364 error("%s doesn't belong to btrfs mount point", subvol);
365 ret = -EINVAL;
366 goto out;
369 s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
370 if (s->mnt_fd < 0) {
371 ret = -errno;
372 error("cannot open '%s': %s", s->root_path, strerror(-ret));
373 goto out;
376 ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
377 if (ret < 0) {
378 error("failed to initialize subvol search: %s",
379 strerror(-ret));
380 goto out;
383 out:
384 return ret;
388 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
390 int ret;
391 u64 flags;
392 int fd = -1;
394 fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
395 if (fd < 0) {
396 ret = -errno;
397 error("cannot open %s: %s", subvol, strerror(-ret));
398 goto out;
401 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
402 if (ret < 0) {
403 ret = -errno;
404 error("failed to get flags for subvolume %s: %s",
405 subvol, strerror(-ret));
406 goto out;
409 if (flags & BTRFS_SUBVOL_RDONLY)
410 ret = 1;
411 else
412 ret = 0;
414 out:
415 if (fd != -1)
416 close(fd);
418 return ret;
421 int cmd_send(int argc, char **argv)
423 char *subvol = NULL;
424 int ret;
425 char outname[PATH_MAX];
426 struct btrfs_send send;
427 u32 i;
428 char *mount_root = NULL;
429 char *snapshot_parent = NULL;
430 u64 root_id = 0;
431 u64 parent_root_id = 0;
432 int full_send = 1;
433 int new_end_cmd_semantic = 0;
434 u64 send_flags = 0;
436 memset(&send, 0, sizeof(send));
437 send.dump_fd = fileno(stdout);
438 outname[0] = 0;
440 while (1) {
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);
447 if (c < 0)
448 break;
450 switch (c) {
451 case 'v':
452 g_verbose++;
453 break;
454 case 'e':
455 new_end_cmd_semantic = 1;
456 break;
457 case 'c':
458 subvol = realpath(optarg, NULL);
459 if (!subvol) {
460 ret = -errno;
461 error("realpath %s failed: %s\n", optarg, strerror(-ret));
462 goto out;
465 ret = init_root_path(&send, subvol);
466 if (ret < 0)
467 goto out;
469 ret = get_root_id(&send, get_subvol_name(send.root_path, subvol),
470 &root_id);
471 if (ret < 0) {
472 error("cannot resolve rootid for %s", subvol);
473 goto out;
476 ret = is_subvol_ro(&send, subvol);
477 if (ret < 0)
478 goto out;
479 if (!ret) {
480 ret = -EINVAL;
481 error("cloned subvolume %s is not read-only", subvol);
482 goto out;
485 ret = add_clone_source(&send, root_id);
486 if (ret < 0) {
487 error("not enough memory");
488 goto out;
490 subvol_uuid_search_finit(&send.sus);
491 free(subvol);
492 subvol = NULL;
493 if (send.mnt_fd >= 0) {
494 close(send.mnt_fd);
495 send.mnt_fd = -1;
497 free(send.root_path);
498 send.root_path = NULL;
499 full_send = 0;
500 break;
501 case 'f':
502 if (arg_copy_path(outname, optarg, sizeof(outname))) {
503 error("output file path too long (%zu)", strlen(optarg));
504 ret = 1;
505 goto out;
507 break;
508 case 'p':
509 if (snapshot_parent) {
510 error("you cannot have more than one parent (-p)");
511 ret = 1;
512 goto out;
514 snapshot_parent = realpath(optarg, NULL);
515 if (!snapshot_parent) {
516 ret = -errno;
517 error("realpath %s failed: %s", optarg, strerror(-ret));
518 goto out;
521 ret = is_subvol_ro(&send, snapshot_parent);
522 if (ret < 0)
523 goto out;
524 if (!ret) {
525 ret = -EINVAL;
526 error("parent subvolume %s is not read-only",
527 snapshot_parent);
528 goto out;
531 full_send = 0;
532 break;
533 case 'i':
534 error("option -i was removed, use -c instead");
535 ret = 1;
536 goto out;
537 case GETOPT_VAL_SEND_NO_DATA:
538 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
539 break;
540 case '?':
541 default:
542 error("send arguments invalid");
543 ret = 1;
544 goto out;
548 if (check_argc_min(argc - optind, 1))
549 usage(cmd_send_usage);
551 if (outname[0]) {
552 send.dump_fd = creat(outname, 0600);
553 if (send.dump_fd == -1) {
554 ret = -errno;
555 error("cannot create '%s': %s", outname, strerror(-ret));
556 goto out;
560 if (isatty(send.dump_fd)) {
561 error(
562 "not dumping send stream into a terminal, redirect it into a file");
563 ret = 1;
564 goto out;
567 /* use first send subvol to determine mount_root */
568 subvol = argv[optind];
570 subvol = realpath(argv[optind], NULL);
571 if (!subvol) {
572 ret = -errno;
573 error("unable to resolve %s", argv[optind]);
574 goto out;
577 ret = init_root_path(&send, subvol);
578 if (ret < 0)
579 goto out;
581 if (snapshot_parent != NULL) {
582 ret = get_root_id(&send,
583 get_subvol_name(send.root_path, snapshot_parent),
584 &parent_root_id);
585 if (ret < 0) {
586 error("could not resolve rootid for %s", snapshot_parent);
587 goto out;
590 ret = add_clone_source(&send, parent_root_id);
591 if (ret < 0) {
592 error("not enough memory");
593 goto out;
597 for (i = optind; i < argc; i++) {
598 free(subvol);
599 subvol = realpath(argv[i], NULL);
600 if (!subvol) {
601 ret = -errno;
602 error("unable to resolve %s", argv[i]);
603 goto out;
606 ret = find_mount_root(subvol, &mount_root);
607 if (ret < 0) {
608 error("find_mount_root failed on %s: %s", subvol,
609 strerror(-ret));
610 goto out;
612 if (ret > 0) {
613 error("%s does not belong to btrfs mount point",
614 subvol);
615 ret = -EINVAL;
616 goto out;
618 if (strcmp(send.root_path, mount_root) != 0) {
619 ret = -EINVAL;
620 error("all subvolumes must be from the same filesystem");
621 goto out;
623 free(mount_root);
625 ret = is_subvol_ro(&send, subvol);
626 if (ret < 0)
627 goto out;
628 if (!ret) {
629 ret = -EINVAL;
630 error("subvolum %s is not read-only", subvol);
631 goto out;
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++) {
639 int is_first_subvol;
640 int is_last_subvol;
642 free(subvol);
643 subvol = argv[i];
645 fprintf(stderr, "At subvol %s\n", subvol);
647 subvol = realpath(subvol, NULL);
648 if (!subvol) {
649 ret = -errno;
650 error("realpath %s failed: %s", argv[i], strerror(-ret));
651 goto out;
654 if (!full_send && !parent_root_id) {
655 ret = find_good_parent(&send, root_id, &parent_root_id);
656 if (ret < 0) {
657 error("parent determination failed for %lld",
658 root_id);
659 goto out;
663 ret = is_subvol_ro(&send, subvol);
664 if (ret < 0)
665 goto out;
666 if (!ret) {
667 ret = -EINVAL;
668 error("subvolume %s is not read-only", subvol);
669 goto out;
672 if (new_end_cmd_semantic) {
673 /* require new kernel */
674 is_first_subvol = (i == optind);
675 is_last_subvol = (i == argc - 1);
676 } else {
677 /* be compatible to old and new kernel */
678 is_first_subvol = 1;
679 is_last_subvol = 1;
681 ret = do_send(&send, parent_root_id, is_first_subvol,
682 is_last_subvol, subvol, send_flags);
683 if (ret < 0)
684 goto out;
686 /* done with this subvol, so add it to the clone sources */
687 ret = add_clone_source(&send, root_id);
688 if (ret < 0) {
689 error("not enough memory");
690 goto out;
693 parent_root_id = 0;
694 full_send = 0;
697 ret = 0;
699 out:
700 free(subvol);
701 free(snapshot_parent);
702 free(send.clone_sources);
703 if (send.mnt_fd >= 0)
704 close(send.mnt_fd);
705 free(send.root_path);
706 subvol_uuid_search_finit(&send.sus);
707 return !!ret;
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.",
724 "\n",
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",
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 NULL