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