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