btrfs-progs: doc quota, sort subcommands alphabetically
[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 #define _GNU_SOURCE
20
21 #include "kerncompat.h"
22
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>
35
36 #include <uuid/uuid.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 static int g_verbose = 0;
48
49 struct btrfs_send {
50         int send_fd;
51         int dump_fd;
52         int mnt_fd;
53
54         u64 *clone_sources;
55         u64 clone_sources_count;
56
57         char *root_path;
58         struct subvol_uuid_search sus;
59 };
60
61 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
62 {
63         struct subvol_info *si;
64
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;
73 }
74
75 static struct subvol_info *get_parent(struct btrfs_send *s, u64 root_id)
76 {
77         struct subvol_info *si_tmp;
78         struct subvol_info *si;
79
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;
84
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;
90 }
91
92 static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found)
93 {
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;
101
102         parent = get_parent(s, root_id);
103         if (!parent) {
104                 ret = -ENOENT;
105                 goto out;
106         }
107
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;
113                 }
114         }
115
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;
125                 }
126
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);
131
132                 if (!parent2) {
133                         ret = -ENOENT;
134                         goto out;
135                 }
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);
143                         }
144                         best_parent = parent2;
145                         parent2 = NULL;
146                         best_diff = tmp;
147                 } else {
148                         free(parent2->path);
149                         free(parent2);
150                         parent2 = NULL;
151                 }
152         }
153
154         if (!best_parent) {
155                 ret = -ENOENT;
156                 goto out;
157         }
158
159 out_found:
160         *found = best_parent->root_id;
161         ret = 0;
162
163 out:
164         if (parent) {
165                 free(parent->path);
166                 free(parent);
167         }
168         if (best_parent) {
169                 free(best_parent->path);
170                 free(best_parent);
171         }
172         return ret;
173 }
174
175 static int add_clone_source(struct btrfs_send *s, u64 root_id)
176 {
177         s->clone_sources = realloc(s->clone_sources,
178                 sizeof(*s->clone_sources) * (s->clone_sources_count + 1));
179
180         if (!s->clone_sources)
181                 return -ENOMEM;
182         s->clone_sources[s->clone_sources_count++] = root_id;
183
184         return 0;
185 }
186
187 static int write_buf(int fd, const void *buf, int size)
188 {
189         int ret;
190         int pos = 0;
191
192         while (pos < size) {
193                 ret = write(fd, (char*)buf + pos, size - pos);
194                 if (ret < 0) {
195                         ret = -errno;
196                         fprintf(stderr, "ERROR: failed to dump stream. %s",
197                                         strerror(-ret));
198                         goto out;
199                 }
200                 if (!ret) {
201                         ret = -EIO;
202                         fprintf(stderr, "ERROR: failed to dump stream. %s",
203                                         strerror(-ret));
204                         goto out;
205                 }
206                 pos += ret;
207         }
208         ret = 0;
209
210 out:
211         return ret;
212 }
213
214 static void *dump_thread(void *arg_)
215 {
216         int ret;
217         struct btrfs_send *s = (struct btrfs_send*)arg_;
218         char buf[4096];
219         int readed;
220
221         while (1) {
222                 readed = read(s->send_fd, buf, sizeof(buf));
223                 if (readed < 0) {
224                         ret = -errno;
225                         fprintf(stderr, "ERROR: failed to read stream from "
226                                         "kernel. %s\n", strerror(-ret));
227                         goto out;
228                 }
229                 if (!readed) {
230                         ret = 0;
231                         goto out;
232                 }
233                 ret = write_buf(s->dump_fd, buf, readed);
234                 if (ret < 0)
235                         goto out;
236         }
237
238 out:
239         if (ret < 0) {
240                 exit(-ret);
241         }
242
243         return ERR_PTR(ret);
244 }
245
246 static int do_send(struct btrfs_send *send, u64 parent_root_id,
247                    int is_first_subvol, int is_last_subvol, char *subvol)
248 {
249         int ret;
250         pthread_t t_read;
251         struct btrfs_ioctl_send_args io_send;
252         void *t_err = NULL;
253         int subvol_fd = -1;
254         int pipefd[2] = {-1, -1};
255
256         subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
257         if (subvol_fd < 0) {
258                 ret = -errno;
259                 fprintf(stderr, "ERROR: open %s failed. %s\n", subvol,
260                                 strerror(-ret));
261                 goto out;
262         }
263
264         ret = pipe(pipefd);
265         if (ret < 0) {
266                 ret = -errno;
267                 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(-ret));
268                 goto out;
269         }
270
271         memset(&io_send, 0, sizeof(io_send));
272         io_send.send_fd = pipefd[1];
273         send->send_fd = pipefd[0];
274
275         if (!ret)
276                 ret = pthread_create(&t_read, NULL, dump_thread,
277                                         send);
278         if (ret) {
279                 ret = -ret;
280                 fprintf(stderr, "ERROR: thread setup failed: %s\n",
281                         strerror(-ret));
282                 goto out;
283         }
284
285         io_send.clone_sources = (__u64*)send->clone_sources;
286         io_send.clone_sources_count = send->clone_sources_count;
287         io_send.parent_root = parent_root_id;
288         if (!is_first_subvol)
289                 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
290         if (!is_last_subvol)
291                 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
292         ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
293         if (ret) {
294                 ret = -errno;
295                 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
296                         strerror(-ret));
297                 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
298                         fprintf(stderr,
299                                 "Try upgrading your kernel or don't use -e.\n");
300                 goto out;
301         }
302         if (g_verbose > 0)
303                 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
304
305         if (g_verbose > 0)
306                 fprintf(stderr, "joining genl thread\n");
307
308         close(pipefd[1]);
309         pipefd[1] = -1;
310
311         ret = pthread_join(t_read, &t_err);
312         if (ret) {
313                 ret = -ret;
314                 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
315                         strerror(-ret));
316                 goto out;
317         }
318         if (t_err) {
319                 ret = (long int)t_err;
320                 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
321                         "(%s)\n", (long int)t_err, strerror(-ret));
322                 goto out;
323         }
324
325         ret = 0;
326
327 out:
328         if (subvol_fd != -1)
329                 close(subvol_fd);
330         if (pipefd[0] != -1)
331                 close(pipefd[0]);
332         if (pipefd[1] != -1)
333                 close(pipefd[1]);
334         return ret;
335 }
336
337 char *get_subvol_name(char *mnt, char *full_path)
338 {
339         int len = strlen(mnt);
340         if (!len)
341                 return full_path;
342         if (mnt[len - 1] != '/')
343                 len += 1;
344
345         return full_path + len;
346 }
347
348 static int init_root_path(struct btrfs_send *s, const char *subvol)
349 {
350         int ret = 0;
351
352         if (s->root_path)
353                 goto out;
354
355         ret = find_mount_root(subvol, &s->root_path);
356         if (ret < 0) {
357                 fprintf(stderr,
358                         "ERROR: failed to determine mount point for %s: %s\n",
359                         subvol, strerror(-ret));
360                 ret = -EINVAL;
361                 goto out;
362         }
363         if (ret > 0) {
364                 fprintf(stderr,
365                         "ERROR: %s doesn't belong to btrfs mount point\n",
366                         subvol);
367                 ret = -EINVAL;
368                 goto out;
369         }
370
371         s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME);
372         if (s->mnt_fd < 0) {
373                 ret = -errno;
374                 fprintf(stderr, "ERROR: can't open '%s': %s\n", s->root_path,
375                         strerror(-ret));
376                 goto out;
377         }
378
379         ret = subvol_uuid_search_init(s->mnt_fd, &s->sus);
380         if (ret < 0) {
381                 fprintf(stderr, "ERROR: failed to initialize subvol search. "
382                                 "%s\n", strerror(-ret));
383                 goto out;
384         }
385
386 out:
387         return ret;
388
389 }
390
391 static int is_subvol_ro(struct btrfs_send *s, char *subvol)
392 {
393         int ret;
394         u64 flags;
395         int fd = -1;
396
397         fd = openat(s->mnt_fd, subvol, O_RDONLY | O_NOATIME);
398         if (fd < 0) {
399                 ret = -errno;
400                 fprintf(stderr, "ERROR: failed to open %s. %s\n",
401                                 subvol, strerror(-ret));
402                 goto out;
403         }
404
405         ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
406         if (ret < 0) {
407                 ret = -errno;
408                 fprintf(stderr, "ERROR: failed to get flags for subvolume. "
409                                 "%s\n", strerror(-ret));
410                 goto out;
411         }
412
413         if (flags & BTRFS_SUBVOL_RDONLY)
414                 ret = 1;
415         else
416                 ret = 0;
417
418 out:
419         if (fd != -1)
420                 close(fd);
421
422         return ret;
423 }
424
425 int cmd_send(int argc, char **argv)
426 {
427         char *subvol = NULL;
428         int c;
429         int ret;
430         char *outname = NULL;
431         struct btrfs_send send;
432         u32 i;
433         char *mount_root = NULL;
434         char *snapshot_parent = NULL;
435         u64 root_id = 0;
436         u64 parent_root_id = 0;
437         int full_send = 1;
438         int new_end_cmd_semantic = 0;
439
440         memset(&send, 0, sizeof(send));
441         send.dump_fd = fileno(stdout);
442
443         while ((c = getopt(argc, argv, "vec:f:i:p:")) != -1) {
444                 switch (c) {
445                 case 'v':
446                         g_verbose++;
447                         break;
448                 case 'e':
449                         new_end_cmd_semantic = 1;
450                         break;
451                 case 'c':
452                         subvol = realpath(optarg, NULL);
453                         if (!subvol) {
454                                 ret = -errno;
455                                 fprintf(stderr, "ERROR: realpath %s failed. "
456                                                 "%s\n", optarg, strerror(-ret));
457                                 goto out;
458                         }
459
460                         ret = init_root_path(&send, subvol);
461                         if (ret < 0)
462                                 goto out;
463
464                         ret = get_root_id(&send, get_subvol_name(send.root_path, subvol),
465                                         &root_id);
466                         if (ret < 0) {
467                                 fprintf(stderr, "ERROR: could not resolve "
468                                                 "root_id for %s\n", subvol);
469                                 goto out;
470                         }
471
472                         ret = is_subvol_ro(&send, subvol);
473                         if (ret < 0)
474                                 goto out;
475                         if (!ret) {
476                                 ret = -EINVAL;
477                                 fprintf(stderr,
478                                 "ERROR: cloned subvol %s is not read-only.\n",
479                                         subvol);
480                                 goto out;
481                         }
482
483                         ret = add_clone_source(&send, root_id);
484                         if (ret < 0) {
485                                 fprintf(stderr, "ERROR: not enough memory\n");
486                                 goto out;
487                         }
488                         subvol_uuid_search_finit(&send.sus);
489                         free(subvol);
490                         subvol = NULL;
491                         if (send.mnt_fd >= 0) {
492                                 close(send.mnt_fd);
493                                 send.mnt_fd = -1;
494                         }
495                         free(send.root_path);
496                         send.root_path = NULL;
497                         full_send = 0;
498                         break;
499                 case 'f':
500                         outname = optarg;
501                         break;
502                 case 'p':
503                         if (snapshot_parent) {
504                                 fprintf(stderr, "ERROR: you cannot have more than one parent (-p)\n");
505                                 ret = 1;
506                                 goto out;
507                         }
508                         snapshot_parent = realpath(optarg, NULL);
509                         if (!snapshot_parent) {
510                                 ret = -errno;
511                                 fprintf(stderr, "ERROR: realpath %s failed. "
512                                                 "%s\n", optarg, strerror(-ret));
513                                 goto out;
514                         }
515
516                         ret = is_subvol_ro(&send, snapshot_parent);
517                         if (ret < 0)
518                                 goto out;
519                         if (!ret) {
520                                 ret = -EINVAL;
521                                 fprintf(stderr,
522                                         "ERROR: parent %s is not read-only.\n",
523                                         snapshot_parent);
524                                 goto out;
525                         }
526
527                         full_send = 0;
528                         break;
529                 case 'i':
530                         fprintf(stderr,
531                                 "ERROR: -i was removed, use -c instead\n");
532                         ret = 1;
533                         goto out;
534                 case '?':
535                 default:
536                         fprintf(stderr, "ERROR: send args invalid.\n");
537                         ret = 1;
538                         goto out;
539                 }
540         }
541
542         if (check_argc_min(argc - optind, 1))
543                 usage(cmd_send_usage);
544
545         if (outname != NULL) {
546                 send.dump_fd = creat(outname, 0600);
547                 if (send.dump_fd == -1) {
548                         ret = -errno;
549                         fprintf(stderr, "ERROR: can't create '%s': %s\n",
550                                         outname, strerror(-ret));
551                         goto out;
552                 }
553         }
554
555         if (isatty(send.dump_fd)) {
556                 fprintf(stderr, 
557                         "ERROR: not dumping send stream into a terminal, "
558                         "redirect it into a file\n");
559                 ret = 1;
560                 goto out;
561         }
562
563         /* use first send subvol to determine mount_root */
564         subvol = argv[optind];
565
566         subvol = realpath(argv[optind], NULL);
567         if (!subvol) {
568                 ret = -errno;
569                 fprintf(stderr, "ERROR: unable to resolve %s\n", argv[optind]);
570                 goto out;
571         }
572
573         ret = init_root_path(&send, subvol);
574         if (ret < 0)
575                 goto out;
576
577         if (snapshot_parent != NULL) {
578                 ret = get_root_id(&send,
579                                 get_subvol_name(send.root_path, snapshot_parent),
580                                 &parent_root_id);
581                 if (ret < 0) {
582                         fprintf(stderr, "ERROR: could not resolve root_id "
583                                         "for %s\n", snapshot_parent);
584                         goto out;
585                 }
586
587                 ret = add_clone_source(&send, parent_root_id);
588                 if (ret < 0) {
589                         fprintf(stderr, "ERROR: not enough memory\n");
590                         goto out;
591                 }
592         }
593
594         for (i = optind; i < argc; i++) {
595                 free(subvol);
596                 subvol = realpath(argv[i], NULL);
597                 if (!subvol) {
598                         ret = -errno;
599                         fprintf(stderr, "ERROR: unable to resolve %s\n", argv[i]);
600                         goto out;
601                 }
602
603                 ret = find_mount_root(subvol, &mount_root);
604                 if (ret < 0) {
605                         fprintf(stderr, "ERROR: find_mount_root failed on %s: "
606                                         "%s\n", subvol,
607                                 strerror(-ret));
608                         goto out;
609                 }
610                 if (ret > 0) {
611                         fprintf(stderr,
612                         "ERROR: %s doesn't belong to btrfs mount point\n",
613                                 subvol);
614                         ret = -EINVAL;
615                         goto out;
616                 }
617                 if (strcmp(send.root_path, mount_root) != 0) {
618                         ret = -EINVAL;
619                         fprintf(stderr, "ERROR: all subvols must be from the "
620                                         "same fs.\n");
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                         fprintf(stderr, "ERROR: %s is not read-only.\n",
631                                         subvol);
632                         goto out;
633                 }
634         }
635
636         for (i = optind; i < argc; i++) {
637                 int is_first_subvol;
638                 int is_last_subvol;
639
640                 free(subvol);
641                 subvol = argv[i];
642
643                 fprintf(stderr, "At subvol %s\n", subvol);
644
645                 subvol = realpath(subvol, NULL);
646                 if (!subvol) {
647                         ret = -errno;
648                         fprintf(stderr, "ERROR: realpath %s failed. "
649                                         "%s\n", argv[i], strerror(-ret));
650                         goto out;
651                 }
652
653                 if (!full_send && !parent_root_id) {
654                         ret = find_good_parent(&send, root_id, &parent_root_id);
655                         if (ret < 0) {
656                                 fprintf(stderr, "ERROR: parent determination failed for %lld\n",
657                                         root_id);
658                                 goto out;
659                         }
660                 }
661
662                 ret = is_subvol_ro(&send, subvol);
663                 if (ret < 0)
664                         goto out;
665                 if (!ret) {
666                         ret = -EINVAL;
667                         fprintf(stderr, "ERROR: %s is not read-only.\n",
668                                         subvol);
669                         goto out;
670                 }
671
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;
680                 }
681                 ret = do_send(&send, parent_root_id, is_first_subvol,
682                               is_last_subvol, subvol);
683                 if (ret < 0)
684                         goto out;
685
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                         fprintf(stderr, "ERROR: not enough memory\n");
690                         goto out;
691                 }
692
693                 parent_root_id = 0;
694                 full_send = 0;
695         }
696
697         ret = 0;
698
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;
708 }
709
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         "By default, this will send the whole subvolume. To do an incremental",
715         "send, use '-p <parent>'. If you want to allow btrfs to clone from",
716         "any additional local snapshots, use '-c <clone-src>' (multiple times",
717         "where applicable). You must not specify clone sources unless you",
718         "guarantee that these snapshots are exactly in the same state on both",
719         "sides, the sender and the receiver. It is allowed to omit the",
720         "'-p <parent>' option when '-c <clone-src>' options are given, in",
721         "which case 'btrfs send' will determine a suitable parent among the",
722         "clone sources itself.",
723         "\n",
724         "-v               Enable verbose debug output. Each occurrence of",
725         "                 this option increases the verbose level more.",
726         "-e               If sending multiple subvols at once, use the new",
727         "                 format and omit the end-cmd between the subvols.",
728         "-p <parent>      Send an incremental stream from <parent> to",
729         "                 <subvol>.",
730         "-c <clone-src>   Use this snapshot as a clone source for an ",
731         "                 incremental send (multiple allowed)",
732         "-f <outfile>     Output is normally written to stdout. To write to",
733         "                 a file, use this option. An alternative would be to",
734         "                 use pipes.",
735         NULL
736 };