bf1d9733eb9cfa38d69360c2b6f7da7dcb6aaaf1
[platform/upstream/btrfs-progs.git] / cmds-send.c
1 /*
2  * Copyright (C) 2012 Alexander Block.  All rights reserved.
3  *
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.
7  *
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.
12  *
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.
17  */
18
19
20 #include "kerncompat.h"
21
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>
37
38 #include "ctree.h"
39 #include "ioctl.h"
40 #include "commands.h"
41 #include "list.h"
42 #include "utils.h"
43
44 #include "send.h"
45 #include "send-utils.h"
46
47 #define SEND_BUFFER_SIZE        (64 * 1024)
48
49 /*
50  * Default is 1 for historical reasons, changing may break scripts that expect
51  * the 'At subvol' message.
52  */
53 static int g_verbose = 1;
54
55 struct btrfs_send {
56         int send_fd;
57         int dump_fd;
58         int mnt_fd;
59
60         u64 *clone_sources;
61         u64 clone_sources_count;
62
63         char *root_path;
64         struct subvol_uuid_search sus;
65 };
66
67 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
68 {
69         struct subvol_info *si;
70
71         si = subvol_uuid_search(&s->sus, 0, NULL, 0, path,
72                         subvol_search_by_path);
73         if (!si)
74                 return -ENOENT;
75         *root_id = si->root_id;
76         free(si->path);
77         free(si);
78         return 0;
79 }
80
81 static struct subvol_info *get_parent(struct btrfs_send *s, u64 root_id)
82 {
83         struct subvol_info *si_tmp;
84         struct subvol_info *si;
85
86         si_tmp = subvol_uuid_search(&s->sus, root_id, NULL, 0, NULL,
87                         subvol_search_by_root_id);
88         if (!si_tmp)
89                 return NULL;
90
91         si = subvol_uuid_search(&s->sus, 0, si_tmp->parent_uuid, 0, NULL,
92                         subvol_search_by_uuid);
93         free(si_tmp->path);
94         free(si_tmp);
95         return si;
96 }
97
98 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
99 {
100         int ret;
101         struct subvol_info *parent = NULL;
102         struct subvol_info *parent2 = NULL;
103         struct subvol_info *best_parent = NULL;
104         __s64 tmp;
105         u64 best_diff = (u64)-1;
106         int i;
107
108         parent = get_parent(s, root_id);
109         if (!parent) {
110                 ret = -ENOENT;
111                 goto out;
112         }
113
114         for (i = 0; i < s->clone_sources_count; i++) {
115                 if (s->clone_sources[i] == parent->root_id) {
116                         best_parent = parent;
117                         parent = NULL;
118                         goto out_found;
119                 }
120         }
121
122         for (i = 0; i < s->clone_sources_count; i++) {
123                 parent2 = get_parent(s, s->clone_sources[i]);
124                 if (!parent2)
125                         continue;
126                 if (parent2->root_id != parent->root_id) {
127                         free(parent2->path);
128                         free(parent2);
129                         parent2 = NULL;
130                         continue;
131                 }
132
133                 free(parent2->path);
134                 free(parent2);
135                 parent2 = subvol_uuid_search(&s->sus, s->clone_sources[i], NULL,
136                                 0, NULL, subvol_search_by_root_id);
137
138                 if (!parent2) {
139                         ret = -ENOENT;
140                         goto out;
141                 }
142                 tmp = parent2->ctransid - parent->ctransid;
143                 if (tmp < 0)
144                         tmp *= -1;
145                 if (tmp < best_diff) {
146                         if (best_parent) {
147                                 free(best_parent->path);
148                                 free(best_parent);
149                         }
150                         best_parent = parent2;
151                         parent2 = NULL;
152                         best_diff = tmp;
153                 } else {
154                         free(parent2->path);
155                         free(parent2);
156                         parent2 = NULL;
157                 }
158         }
159
160         if (!best_parent) {
161                 ret = -ENOENT;
162                 goto out;
163         }
164
165 out_found:
166         *found = best_parent->root_id;
167         ret = 0;
168
169 out:
170         if (parent) {
171                 free(parent->path);
172                 free(parent);
173         }
174         if (best_parent) {
175                 free(best_parent->path);
176                 free(best_parent);
177         }
178         return ret;
179 }
180
181 static int add_clone_source(struct btrfs_send *s, u64 root_id)
182 {
183         void *tmp;
184
185         tmp = s->clone_sources;
186         s->clone_sources = realloc(s->clone_sources,
187                 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
188
189         if (!s->clone_sources) {
190                 free(tmp);
191                 return -ENOMEM;
192         }
193         s->clone_sources[s->clone_sources_count++] = root_id;
194
195         return 0;
196 }
197
198 static int write_buf(int fd, const void *buf, int size)
199 {
200         int ret;
201         int pos = 0;
202
203         while (pos < size) {
204                 ret = write(fd, (char*)buf + pos, size - pos);
205                 if (ret < 0) {
206                         ret = -errno;
207                         error("failed to dump stream: %s", strerror(-ret));
208                         goto out;
209                 }
210                 if (!ret) {
211                         ret = -EIO;
212                         error("failed to dump stream: %s", strerror(-ret));
213                         goto out;
214                 }
215                 pos += ret;
216         }
217         ret = 0;
218
219 out:
220         return ret;
221 }
222
223 static void *dump_thread(void *arg_)
224 {
225         int ret;
226         struct btrfs_send *s = (struct btrfs_send*)arg_;
227         char buf[SEND_BUFFER_SIZE];
228
229         while (1) {
230                 ssize_t rbytes;
231
232                 rbytes = read(s->send_fd, buf, sizeof(buf));
233                 if (rbytes < 0) {
234                         ret = -errno;
235                         error("failed to read stream from kernel: %s\n",
236                                 strerror(-ret));
237                         goto out;
238                 }
239                 if (!rbytes) {
240                         ret = 0;
241                         goto out;
242                 }
243                 ret = write_buf(s->dump_fd, buf, rbytes);
244                 if (ret < 0)
245                         goto out;
246         }
247
248 out:
249         if (ret < 0) {
250                 exit(-ret);
251         }
252
253         return ERR_PTR(ret);
254 }
255
256 static int do_send(struct btrfs_send *send, u64 parent_root_id,
257                    int is_first_subvol, int is_last_subvol, const char *subvol,
258                    u64 flags)
259 {
260         int ret;
261         pthread_t t_read;
262         struct btrfs_ioctl_send_args io_send;
263         void *t_err = NULL;
264         int subvol_fd = -1;
265         int pipefd[2] = {-1, -1};
266
267         subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
268         if (subvol_fd < 0) {
269                 ret = -errno;
270                 error("cannot open %s: %s", subvol, strerror(-ret));
271                 goto out;
272         }
273
274         ret = pipe(pipefd);
275         if (ret < 0) {
276                 ret = -errno;
277                 error("pipe failed: %s", strerror(-ret));
278                 goto out;
279         }
280
281         memset(&io_send, 0, sizeof(io_send));
282         io_send.send_fd = pipefd[1];
283         send->send_fd = pipefd[0];
284
285         if (!ret)
286                 ret = pthread_create(&t_read, NULL, dump_thread,
287                                         send);
288         if (ret) {
289                 ret = -ret;
290                 error("thread setup failed: %s", strerror(-ret));
291                 goto out;
292         }
293
294         io_send.flags = flags;
295         io_send.clone_sources = (__u64*)send->clone_sources;
296         io_send.clone_sources_count = send->clone_sources_count;
297         io_send.parent_root = parent_root_id;
298         if (!is_first_subvol)
299                 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
300         if (!is_last_subvol)
301                 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
302         ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
303         if (ret < 0) {
304                 ret = -errno;
305                 error("send ioctl failed with %d: %s", ret, strerror(-ret));
306                 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
307                         fprintf(stderr,
308                                 "Try upgrading your kernel or don't use -e.\n");
309                 goto out;
310         }
311         if (g_verbose > 1)
312                 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
313
314         if (g_verbose > 1)
315                 fprintf(stderr, "joining genl thread\n");
316
317         close(pipefd[1]);
318         pipefd[1] = -1;
319
320         ret = pthread_join(t_read, &t_err);
321         if (ret) {
322                 ret = -ret;
323                 error("pthread_join failed: %s", strerror(-ret));
324                 goto out;
325         }
326         if (t_err) {
327                 ret = (long int)t_err;
328                 error("failed to process send stream, ret=%ld (%s)",
329                                 (long int)t_err, strerror(-ret));
330                 goto out;
331         }
332
333         ret = 0;
334
335 out:
336         if (subvol_fd != -1)
337                 close(subvol_fd);
338         if (pipefd[0] != -1)
339                 close(pipefd[0]);
340         if (pipefd[1] != -1)
341                 close(pipefd[1]);
342         return ret;
343 }
344
345 static int init_root_path(struct btrfs_send *s, const char *subvol)
346 {
347         int ret = 0;
348
349         if (s->root_path)
350                 goto out;
351
352         ret = find_mount_root(subvol, &s->root_path);
353         if (ret < 0) {
354                 error("failed to determine mount point for %s: %s",
355                         subvol, strerror(-ret));
356                 ret = -EINVAL;
357                 goto out;
358         }
359         if (ret > 0) {
360                 error("%s doesn't belong to btrfs mount point", subvol);
361                 ret = -EINVAL;
362                 goto out;
363         }
364
365         s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
366         if (s->mnt_fd < 0) {
367                 ret = -errno;
368                 error("cannot open '%s': %s", s->root_path, strerror(-ret));
369                 goto out;
370         }
371
372         ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
373         if (ret < 0) {
374                 error("failed to initialize subvol search: %s",
375                         strerror(-ret));
376                 goto out;
377         }
378
379 out:
380         return ret;
381
382 }
383
384 static int is_subvol_ro(struct btrfs_send *s, const char *subvol)
385 {
386         int ret;
387         u64 flags;
388         int fd = -1;
389
390         fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
391         if (fd < 0) {
392                 ret = -errno;
393                 error("cannot open %s: %s", subvol, strerror(-ret));
394                 goto out;
395         }
396
397         ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
398         if (ret < 0) {
399                 ret = -errno;
400                 error("failed to get flags for subvolume %s: %s",
401                         subvol, strerror(-ret));
402                 goto out;
403         }
404
405         if (flags & BTRFS_SUBVOL_RDONLY)
406                 ret = 1;
407         else
408                 ret = 0;
409
410 out:
411         if (fd != -1)
412                 close(fd);
413
414         return ret;
415 }
416
417 int cmd_send(int argc, char **argv)
418 {
419         char *subvol = NULL;
420         int ret;
421         char outname[PATH_MAX];
422         struct btrfs_send send;
423         u32 i;
424         char *mount_root = NULL;
425         char *snapshot_parent = NULL;
426         u64 root_id = 0;
427         u64 parent_root_id = 0;
428         int full_send = 1;
429         int new_end_cmd_semantic = 0;
430         u64 send_flags = 0;
431
432         memset(&send, 0, sizeof(send));
433         send.dump_fd = fileno(stdout);
434         outname[0] = 0;
435
436         while (1) {
437                 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
438                 static const struct option long_options[] = {
439                         { "verbose", no_argument, NULL, 'v' },
440                         { "quiet", no_argument, NULL, 'q' },
441                         { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
442                 };
443                 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
444
445                 if (c < 0)
446                         break;
447
448                 switch (c) {
449                 case 'v':
450                         g_verbose++;
451                         break;
452                 case 'q':
453                         g_verbose = 0;
454                         break;
455                 case 'e':
456                         new_end_cmd_semantic = 1;
457                         break;
458                 case 'c':
459                         subvol = realpath(optarg, NULL);
460                         if (!subvol) {
461                                 ret = -errno;
462                                 error("realpath %s failed: %s\n", optarg, strerror(-ret));
463                                 goto out;
464                         }
465
466                         ret = init_root_path(&send, subvol);
467                         if (ret < 0)
468                                 goto out;
469
470                         ret = get_root_id(&send,
471                                 subvol_strip_mountpoint(send.root_path, subvol),
472                                 &root_id);
473                         if (ret < 0) {
474                                 error("cannot resolve rootid for %s", subvol);
475                                 goto out;
476                         }
477
478                         ret = is_subvol_ro(&send, subvol);
479                         if (ret < 0)
480                                 goto out;
481                         if (!ret) {
482                                 ret = -EINVAL;
483                                 error("cloned subvolume %s is not read-only", subvol);
484                                 goto out;
485                         }
486
487                         ret = add_clone_source(&send, root_id);
488                         if (ret < 0) {
489                                 error("cannot add clone source: %s", strerror(-ret));
490                                 goto out;
491                         }
492                         subvol_uuid_search_finit(&send.sus);
493                         free(subvol);
494                         subvol = NULL;
495                         if (send.mnt_fd >= 0) {
496                                 close(send.mnt_fd);
497                                 send.mnt_fd = -1;
498                         }
499                         free(send.root_path);
500                         send.root_path = NULL;
501                         full_send = 0;
502                         break;
503                 case 'f':
504                         if (arg_copy_path(outname, optarg, sizeof(outname))) {
505                                 error("output file path too long (%zu)", strlen(optarg));
506                                 ret = 1;
507                                 goto out;
508                         }
509                         break;
510                 case 'p':
511                         if (snapshot_parent) {
512                                 error("you cannot have more than one parent (-p)");
513                                 ret = 1;
514                                 goto out;
515                         }
516                         snapshot_parent = realpath(optarg, NULL);
517                         if (!snapshot_parent) {
518                                 ret = -errno;
519                                 error("realpath %s failed: %s", optarg, strerror(-ret));
520                                 goto out;
521                         }
522
523                         ret = is_subvol_ro(&send, snapshot_parent);
524                         if (ret < 0)
525                                 goto out;
526                         if (!ret) {
527                                 ret = -EINVAL;
528                                 error("parent subvolume %s is not read-only",
529                                         snapshot_parent);
530                                 goto out;
531                         }
532
533                         full_send = 0;
534                         break;
535                 case 'i':
536                         error("option -i was removed, use -c instead");
537                         ret = 1;
538                         goto out;
539                 case GETOPT_VAL_SEND_NO_DATA:
540                         send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
541                         break;
542                 case '?':
543                 default:
544                         error("send arguments invalid");
545                         ret = 1;
546                         goto out;
547                 }
548         }
549
550         if (check_argc_min(argc - optind, 1))
551                 usage(cmd_send_usage);
552
553         if (outname[0]) {
554                 send.dump_fd = creat(outname, 0600);
555                 if (send.dump_fd == -1) {
556                         ret = -errno;
557                         error("cannot create '%s': %s", outname, strerror(-ret));
558                         goto out;
559                 }
560         }
561
562         if (isatty(send.dump_fd)) {
563                 error(
564             "not dumping send stream into a terminal, redirect it into a file");
565                 ret = 1;
566                 goto out;
567         }
568
569         /* use first send subvol to determine mount_root */
570         subvol = realpath(argv[optind], NULL);
571         if (!subvol) {
572                 ret = -errno;
573                 error("unable to resolve %s", argv[optind]);
574                 goto out;
575         }
576
577         ret = init_root_path(&send, subvol);
578         if (ret < 0)
579                 goto out;
580
581         if (snapshot_parent != NULL) {
582                 ret = get_root_id(&send,
583                         subvol_strip_mountpoint(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;
588                 }
589
590                 ret = add_clone_source(&send, parent_root_id);
591                 if (ret < 0) {
592                         error("cannot add clone source: %s", strerror(-ret));
593                         goto out;
594                 }
595         }
596
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;
604                 }
605
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;
611                 }
612                 if (ret > 0) {
613                         error("%s does not belong to btrfs mount point",
614                                 subvol);
615                         ret = -EINVAL;
616                         goto out;
617                 }
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;
622                 }
623                 free(mount_root);
624
625                 ret = is_subvol_ro(&send, subvol);
626                 if (ret < 0)
627                         goto out;
628                 if (!ret) {
629                         ret = -EINVAL;
630                         error("subvolume %s is not read-only", subvol);
631                         goto out;
632                 }
633         }
634
635         if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
636                 if (g_verbose > 1)
637                         fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
638
639         for (i = optind; i < argc; i++) {
640                 int is_first_subvol;
641                 int is_last_subvol;
642
643                 free(subvol);
644                 subvol = argv[i];
645
646                 if (g_verbose > 0)
647                         fprintf(stderr, "At subvol %s\n", subvol);
648
649                 subvol = realpath(subvol, NULL);
650                 if (!subvol) {
651                         ret = -errno;
652                         error("realpath %s failed: %s", argv[i], strerror(-ret));
653                         goto out;
654                 }
655
656                 if (!full_send && root_id) {
657                         ret = find_good_parent(&send, root_id, &parent_root_id);
658                         if (ret < 0) {
659                                 error("parent determination failed for %lld",
660                                         root_id);
661                                 goto out;
662                         }
663                 }
664
665                 if (new_end_cmd_semantic) {
666                         /* require new kernel */
667                         is_first_subvol = (i == optind);
668                         is_last_subvol = (i == argc - 1);
669                 } else {
670                         /* be compatible to old and new kernel */
671                         is_first_subvol = 1;
672                         is_last_subvol = 1;
673                 }
674                 ret = do_send(&send, parent_root_id, is_first_subvol,
675                               is_last_subvol, subvol, send_flags);
676                 if (ret < 0)
677                         goto out;
678
679                 if (!full_send && root_id) {
680                         /* done with this subvol, so add it to the clone sources */
681                         ret = add_clone_source(&send, root_id);
682                         if (ret < 0) {
683                                 error("cannot add clone source: %s", strerror(-ret));
684                                 goto out;
685                         }
686                 }
687         }
688
689         ret = 0;
690
691 out:
692         free(subvol);
693         free(snapshot_parent);
694         free(send.clone_sources);
695         if (send.mnt_fd >= 0)
696                 close(send.mnt_fd);
697         free(send.root_path);
698         subvol_uuid_search_finit(&send.sus);
699         return !!ret;
700 }
701
702 const char * const cmd_send_usage[] = {
703         "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
704         "Send the subvolume(s) to stdout.",
705         "Sends the subvolume(s) specified by <subvol> to stdout.",
706         "<subvol> should be read-only here.",
707         "By default, this will send the whole subvolume. To do an incremental",
708         "send, use '-p <parent>'. If you want to allow btrfs to clone from",
709         "any additional local snapshots, use '-c <clone-src>' (multiple times",
710         "where applicable). You must not specify clone sources unless you",
711         "guarantee that these snapshots are exactly in the same state on both",
712         "sides, the sender and the receiver. It is allowed to omit the",
713         "'-p <parent>' option when '-c <clone-src>' options are given, in",
714         "which case 'btrfs send' will determine a suitable parent among the",
715         "clone sources itself.",
716         "\n",
717         "-e               If sending multiple subvols at once, use the new",
718         "                 format and omit the end-cmd between the subvols.",
719         "-p <parent>      Send an incremental stream from <parent> to",
720         "                 <subvol>.",
721         "-c <clone-src>   Use this snapshot as a clone source for an ",
722         "                 incremental send (multiple allowed)",
723         "-f <outfile>     Output is normally written to stdout. To write to",
724         "                 a file, use this option. An alternative would be to",
725         "                 use pipes.",
726         "--no-data        send in NO_FILE_DATA mode, Note: the output stream",
727         "                 does not contain any file data and thus cannot be used",
728         "                 to transfer changes. This mode is faster and useful to",
729         "                 show the differences in metadata.",
730         "-v|--verbose     enable verbose output to stderr, each occurrence of",
731         "                 this option increases verbosity",
732         "-q|--quiet       suppress all messages, except errors",
733         NULL
734 };