Merge branch 'for-chris' of git://repo.or.cz/btrfs-progs-unstable/devel into raid56
[btrfs-progs-unstable/devel.git] / cmds-receive.c
blob973687f31c6474132e5fea8c422e9cb058a9ba9e
1 /*
2 * Copyright (C) 2012 Alexander Block. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
19 #define _GNU_SOURCE
20 #define _POSIX_C_SOURCE 200809
21 #define _XOPEN_SOURCE 700
22 #define _BSD_SOURCE
24 #include "kerncompat.h"
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <math.h>
32 #include <ftw.h>
33 #include <wait.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/xattr.h>
41 #include <uuid/uuid.h>
43 #include "ctree.h"
44 #include "ioctl.h"
45 #include "commands.h"
46 #include "list.h"
48 #include "send.h"
49 #include "send-stream.h"
50 #include "send-utils.h"
52 static int g_verbose = 0;
54 struct btrfs_receive
56 int mnt_fd;
58 int write_fd;
59 char *write_path;
61 char *root_path;
62 char *full_subvol_path;
64 struct subvol_info *cur_subvol;
65 struct subvol_info *parent_subvol;
67 struct subvol_uuid_search sus;
70 static int finish_subvol(struct btrfs_receive *r)
72 int ret;
73 int subvol_fd = -1;
74 int info_fd = -1;
75 struct btrfs_ioctl_received_subvol_args rs_args;
76 char uuid_str[128];
77 u64 flags;
79 if (r->cur_subvol == NULL)
80 return 0;
82 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
83 O_RDONLY | O_NOATIME);
84 if (subvol_fd < 0) {
85 ret = -errno;
86 fprintf(stderr, "ERROR: open %s failed. %s\n",
87 r->cur_subvol->path, strerror(-ret));
88 goto out;
91 memset(&rs_args, 0, sizeof(rs_args));
92 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
93 rs_args.stransid = r->cur_subvol->stransid;
95 if (g_verbose >= 1) {
96 uuid_unparse((u8*)rs_args.uuid, uuid_str);
97 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
98 "stransid=%llu\n", uuid_str, rs_args.stransid);
101 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
102 if (ret < 0) {
103 ret = -errno;
104 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
105 strerror(-ret));
106 goto out;
108 r->cur_subvol->rtransid = rs_args.rtransid;
110 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
111 if (ret < 0) {
112 ret = -errno;
113 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
114 strerror(-ret));
115 goto out;
118 flags |= BTRFS_SUBVOL_RDONLY;
120 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
121 if (ret < 0) {
122 ret = -errno;
123 fprintf(stderr, "ERROR: failed to make subvolume read only. "
124 "%s\n", strerror(-ret));
125 goto out;
128 subvol_uuid_search_add(&r->sus, r->cur_subvol);
129 r->cur_subvol = NULL;
130 ret = 0;
132 out:
133 if (subvol_fd != -1)
134 close(subvol_fd);
135 if (info_fd != -1)
136 close(info_fd);
137 return ret;
140 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
141 void *user)
143 int ret;
144 struct btrfs_receive *r = user;
145 struct btrfs_ioctl_vol_args args_v1;
146 char uuid_str[128];
148 ret = finish_subvol(r);
149 if (ret < 0)
150 goto out;
152 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
153 r->parent_subvol = NULL;
155 r->cur_subvol->path = strdup(path);
156 r->full_subvol_path = path_cat(r->root_path, path);
158 fprintf(stderr, "At subvol %s\n", path);
160 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
161 r->cur_subvol->stransid = ctransid;
163 if (g_verbose) {
164 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
165 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
166 path, uuid_str,
167 r->cur_subvol->stransid);
170 memset(&args_v1, 0, sizeof(args_v1));
171 strcpy(args_v1.name, path);
172 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
173 if (ret < 0) {
174 ret = -errno;
175 fprintf(stderr, "ERROR: creating subvolume %s failed. "
176 "%s\n", path, strerror(-ret));
177 goto out;
180 out:
181 return ret;
184 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
185 const u8 *parent_uuid, u64 parent_ctransid,
186 void *user)
188 int ret;
189 struct btrfs_receive *r = user;
190 char uuid_str[128];
191 struct btrfs_ioctl_vol_args_v2 args_v2;
193 ret = finish_subvol(r);
194 if (ret < 0)
195 goto out;
197 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
198 r->parent_subvol = NULL;
200 r->cur_subvol->path = strdup(path);
201 r->full_subvol_path = path_cat(r->root_path, path);
203 fprintf(stderr, "At snapshot %s\n", path);
205 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
206 r->cur_subvol->stransid = ctransid;
208 if (g_verbose) {
209 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
210 fprintf(stderr, "receiving snapshot %s uuid=%s, "
211 "ctransid=%llu ", path, uuid_str,
212 r->cur_subvol->stransid);
213 uuid_unparse(parent_uuid, uuid_str);
214 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
215 uuid_str, parent_ctransid);
218 memset(&args_v2, 0, sizeof(args_v2));
219 strcpy(args_v2.name, path);
221 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
222 parent_ctransid, NULL, subvol_search_by_received_uuid);
223 if (!r->parent_subvol) {
224 ret = -ENOENT;
225 fprintf(stderr, "ERROR: could not find parent subvolume\n");
226 goto out;
229 /*if (rs_args.ctransid > rs_args.rtransid) {
230 if (!r->force) {
231 ret = -EINVAL;
232 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
233 goto out;
234 } else {
235 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
239 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
240 O_RDONLY | O_NOATIME);
241 if (args_v2.fd < 0) {
242 ret = -errno;
243 fprintf(stderr, "ERROR: open %s failed. %s\n",
244 r->parent_subvol->path, strerror(-ret));
245 goto out;
248 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
249 close(args_v2.fd);
250 if (ret < 0) {
251 ret = -errno;
252 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
253 "failed. %s\n", r->parent_subvol->path,
254 path, strerror(-ret));
255 goto out;
258 out:
259 return ret;
262 static int process_mkfile(const char *path, void *user)
264 int ret;
265 struct btrfs_receive *r = user;
266 char *full_path = path_cat(r->full_subvol_path, path);
268 if (g_verbose >= 1)
269 fprintf(stderr, "mkfile %s\n", path);
271 ret = creat(full_path, 0600);
272 if (ret < 0) {
273 ret = -errno;
274 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
275 strerror(-ret));
276 goto out;
278 close(ret);
279 ret = 0;
281 out:
282 free(full_path);
283 return ret;
286 static int process_mkdir(const char *path, void *user)
288 int ret;
289 struct btrfs_receive *r = user;
290 char *full_path = path_cat(r->full_subvol_path, path);
292 if (g_verbose >= 1)
293 fprintf(stderr, "mkdir %s\n", path);
295 ret = mkdir(full_path, 0700);
296 if (ret < 0) {
297 ret = -errno;
298 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
299 strerror(-ret));
302 free(full_path);
303 return ret;
306 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
308 int ret;
309 struct btrfs_receive *r = user;
310 char *full_path = path_cat(r->full_subvol_path, path);
312 if (g_verbose >= 1)
313 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
314 path, mode, dev);
316 ret = mknod(full_path, mode & S_IFMT, dev);
317 if (ret < 0) {
318 ret = -errno;
319 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
320 strerror(-ret));
323 free(full_path);
324 return ret;
327 static int process_mkfifo(const char *path, void *user)
329 int ret;
330 struct btrfs_receive *r = user;
331 char *full_path = path_cat(r->full_subvol_path, path);
333 if (g_verbose >= 1)
334 fprintf(stderr, "mkfifo %s\n", path);
336 ret = mkfifo(full_path, 0600);
337 if (ret < 0) {
338 ret = -errno;
339 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
340 strerror(-ret));
343 free(full_path);
344 return ret;
347 static int process_mksock(const char *path, void *user)
349 int ret;
350 struct btrfs_receive *r = user;
351 char *full_path = path_cat(r->full_subvol_path, path);
353 if (g_verbose >= 1)
354 fprintf(stderr, "mksock %s\n", path);
356 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
357 if (ret < 0) {
358 ret = -errno;
359 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
360 strerror(-ret));
363 free(full_path);
364 return ret;
367 static int process_symlink(const char *path, const char *lnk, void *user)
369 int ret;
370 struct btrfs_receive *r = user;
371 char *full_path = path_cat(r->full_subvol_path, path);
373 if (g_verbose >= 1)
374 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
376 ret = symlink(lnk, full_path);
377 if (ret < 0) {
378 ret = -errno;
379 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
380 lnk, strerror(-ret));
383 free(full_path);
384 return ret;
387 static int process_rename(const char *from, const char *to, void *user)
389 int ret;
390 struct btrfs_receive *r = user;
391 char *full_from = path_cat(r->full_subvol_path, from);
392 char *full_to = path_cat(r->full_subvol_path, to);
394 if (g_verbose >= 1)
395 fprintf(stderr, "rename %s -> %s\n", from, to);
397 ret = rename(full_from, full_to);
398 if (ret < 0) {
399 ret = -errno;
400 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
401 to, strerror(-ret));
404 free(full_from);
405 free(full_to);
406 return ret;
409 static int process_link(const char *path, const char *lnk, void *user)
411 int ret;
412 struct btrfs_receive *r = user;
413 char *full_path = path_cat(r->full_subvol_path, path);
414 char *full_link_path = path_cat(r->full_subvol_path, lnk);
416 if (g_verbose >= 1)
417 fprintf(stderr, "link %s -> %s\n", path, lnk);
419 ret = link(full_link_path, full_path);
420 if (ret < 0) {
421 ret = -errno;
422 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
423 lnk, strerror(-ret));
426 free(full_path);
427 free(full_link_path);
428 return ret;
432 static int process_unlink(const char *path, void *user)
434 int ret;
435 struct btrfs_receive *r = user;
436 char *full_path = path_cat(r->full_subvol_path, path);
438 if (g_verbose >= 1)
439 fprintf(stderr, "unlink %s\n", path);
441 ret = unlink(full_path);
442 if (ret < 0) {
443 ret = -errno;
444 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
445 strerror(-ret));
448 free(full_path);
449 return ret;
452 static int process_rmdir(const char *path, void *user)
454 int ret;
455 struct btrfs_receive *r = user;
456 char *full_path = path_cat(r->full_subvol_path, path);
458 if (g_verbose >= 1)
459 fprintf(stderr, "rmdir %s\n", path);
461 ret = rmdir(full_path);
462 if (ret < 0) {
463 ret = -errno;
464 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
465 strerror(-ret));
468 free(full_path);
469 return ret;
473 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
475 int ret = 0;
477 if (r->write_fd != -1) {
478 if (strcmp(r->write_path, path) == 0)
479 goto out;
480 close(r->write_fd);
481 r->write_fd = -1;
484 r->write_fd = open(path, O_RDWR);
485 if (r->write_fd < 0) {
486 ret = -errno;
487 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
488 strerror(-ret));
489 goto out;
491 free(r->write_path);
492 r->write_path = strdup(path);
494 out:
495 return ret;
498 static int close_inode_for_write(struct btrfs_receive *r)
500 int ret = 0;
502 if(r->write_fd == -1)
503 goto out;
505 close(r->write_fd);
506 r->write_fd = -1;
507 r->write_path[0] = 0;
509 out:
510 return ret;
513 static int process_write(const char *path, const void *data, u64 offset,
514 u64 len, void *user)
516 int ret = 0;
517 struct btrfs_receive *r = user;
518 char *full_path = path_cat(r->full_subvol_path, path);
519 u64 pos = 0;
520 int w;
522 ret = open_inode_for_write(r, full_path);
523 if (ret < 0)
524 goto out;
526 while (pos < len) {
527 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
528 offset + pos);
529 if (w < 0) {
530 ret = -errno;
531 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
532 path, strerror(-ret));
533 goto out;
535 pos += w;
538 out:
539 free(full_path);
540 return ret;
543 static int process_clone(const char *path, u64 offset, u64 len,
544 const u8 *clone_uuid, u64 clone_ctransid,
545 const char *clone_path, u64 clone_offset,
546 void *user)
548 int ret = 0;
549 struct btrfs_receive *r = user;
550 struct btrfs_ioctl_clone_range_args clone_args;
551 struct subvol_info *si = NULL;
552 char *full_path = path_cat(r->full_subvol_path, path);
553 char *subvol_path = NULL;
554 char *full_clone_path = NULL;
555 int clone_fd = -1;
557 ret = open_inode_for_write(r, full_path);
558 if (ret < 0)
559 goto out;
561 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
562 subvol_search_by_received_uuid);
563 if (!si) {
564 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
565 BTRFS_FSID_SIZE) == 0) {
566 /* TODO check generation of extent */
567 subvol_path = strdup(r->cur_subvol->path);
568 } else {
569 ret = -ENOENT;
570 fprintf(stderr, "ERROR: did not find source subvol.\n");
571 goto out;
573 } else {
574 /*if (rs_args.ctransid > rs_args.rtransid) {
575 if (!r->force) {
576 ret = -EINVAL;
577 fprintf(stderr, "ERROR: subvolume %s was "
578 "modified after it was "
579 "received.\n",
580 r->subvol_parent_name);
581 goto out;
582 } else {
583 fprintf(stderr, "WARNING: subvolume %s was "
584 "modified after it was "
585 "received.\n",
586 r->subvol_parent_name);
589 subvol_path = strdup(si->path);
592 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
594 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
595 if (clone_fd < 0) {
596 ret = -errno;
597 fprintf(stderr, "ERROR: failed to open %s. %s\n",
598 full_clone_path, strerror(-ret));
599 goto out;
602 clone_args.src_fd = clone_fd;
603 clone_args.src_offset = clone_offset;
604 clone_args.src_length = len;
605 clone_args.dest_offset = offset;
606 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
607 if (ret) {
608 ret = -errno;
609 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
610 path, strerror(-ret));
611 goto out;
614 out:
615 free(full_path);
616 free(full_clone_path);
617 free(subvol_path);
618 if (clone_fd != -1)
619 close(clone_fd);
620 return ret;
624 static int process_set_xattr(const char *path, const char *name,
625 const void *data, int len, void *user)
627 int ret = 0;
628 struct btrfs_receive *r = user;
629 char *full_path = path_cat(r->full_subvol_path, path);
631 if (g_verbose >= 1) {
632 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
633 "data=%.*s\n", path, name, len,
634 len, (char*)data);
637 ret = lsetxattr(full_path, name, data, len, 0);
638 if (ret < 0) {
639 ret = -errno;
640 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
641 path, name, len, (char*)data, strerror(-ret));
642 goto out;
645 out:
646 free(full_path);
647 return ret;
650 static int process_remove_xattr(const char *path, const char *name, void *user)
652 int ret = 0;
653 struct btrfs_receive *r = user;
654 char *full_path = path_cat(r->full_subvol_path, path);
656 if (g_verbose >= 1) {
657 fprintf(stderr, "remove_xattr %s - name=%s\n",
658 path, name);
661 ret = lremovexattr(full_path, name);
662 if (ret < 0) {
663 ret = -errno;
664 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
665 path, name, strerror(-ret));
666 goto out;
669 out:
670 free(full_path);
671 return ret;
674 static int process_truncate(const char *path, u64 size, void *user)
676 int ret = 0;
677 struct btrfs_receive *r = user;
678 char *full_path = path_cat(r->full_subvol_path, path);
680 if (g_verbose >= 1)
681 fprintf(stderr, "truncate %s size=%llu\n", path, size);
683 ret = truncate(full_path, size);
684 if (ret < 0) {
685 ret = -errno;
686 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
687 path, strerror(-ret));
688 goto out;
691 out:
692 free(full_path);
693 return ret;
696 static int process_chmod(const char *path, u64 mode, void *user)
698 int ret = 0;
699 struct btrfs_receive *r = user;
700 char *full_path = path_cat(r->full_subvol_path, path);
702 if (g_verbose >= 1)
703 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
705 ret = chmod(full_path, mode);
706 if (ret < 0) {
707 ret = -errno;
708 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
709 path, strerror(-ret));
710 goto out;
713 out:
714 free(full_path);
715 return ret;
718 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
720 int ret = 0;
721 struct btrfs_receive *r = user;
722 char *full_path = path_cat(r->full_subvol_path, path);
724 if (g_verbose >= 1)
725 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
726 uid, gid);
728 ret = lchown(full_path, uid, gid);
729 if (ret < 0) {
730 ret = -errno;
731 fprintf(stderr, "ERROR: chown %s failed. %s\n",
732 path, strerror(-ret));
733 goto out;
736 out:
737 free(full_path);
738 return ret;
741 static int process_utimes(const char *path, struct timespec *at,
742 struct timespec *mt, struct timespec *ct,
743 void *user)
745 int ret = 0;
746 struct btrfs_receive *r = user;
747 char *full_path = path_cat(r->full_subvol_path, path);
748 struct timespec tv[2];
750 if (g_verbose >= 1)
751 fprintf(stderr, "utimes %s\n", path);
753 tv[0] = *at;
754 tv[1] = *mt;
755 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
756 if (ret < 0) {
757 ret = -errno;
758 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
759 path, strerror(-ret));
760 goto out;
763 out:
764 free(full_path);
765 return ret;
769 struct btrfs_send_ops send_ops = {
770 .subvol = process_subvol,
771 .snapshot = process_snapshot,
772 .mkfile = process_mkfile,
773 .mkdir = process_mkdir,
774 .mknod = process_mknod,
775 .mkfifo = process_mkfifo,
776 .mksock = process_mksock,
777 .symlink = process_symlink,
778 .rename = process_rename,
779 .link = process_link,
780 .unlink = process_unlink,
781 .rmdir = process_rmdir,
782 .write = process_write,
783 .clone = process_clone,
784 .set_xattr = process_set_xattr,
785 .remove_xattr = process_remove_xattr,
786 .truncate = process_truncate,
787 .chmod = process_chmod,
788 .chown = process_chown,
789 .utimes = process_utimes,
792 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
794 int ret;
795 int end = 0;
797 r->root_path = strdup(tomnt);
798 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
799 if (r->mnt_fd < 0) {
800 ret = -errno;
801 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
802 strerror(-ret));
803 goto out;
806 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
807 if (ret < 0)
808 return ret;
810 r->write_fd = -1;
812 while (!end) {
813 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
814 if (ret < 0)
815 goto out;
816 if (ret)
817 end = 1;
819 ret = close_inode_for_write(r);
820 if (ret < 0)
821 goto out;
822 ret = finish_subvol(r);
823 if (ret < 0)
824 goto out;
826 ret = 0;
828 out:
829 return ret;
832 static int do_cmd_receive(int argc, char **argv)
834 int c;
835 char *tomnt = NULL;
836 char *fromfile = NULL;
837 struct btrfs_receive r;
838 int receive_fd = fileno(stdin);
840 int ret;
842 memset(&r, 0, sizeof(r));
844 while ((c = getopt(argc, argv, "vf:")) != -1) {
845 switch (c) {
846 case 'v':
847 g_verbose++;
848 break;
849 case 'f':
850 fromfile = optarg;
851 break;
852 case '?':
853 default:
854 fprintf(stderr, "ERROR: receive args invalid.\n");
855 return 1;
859 if (optind + 1 != argc) {
860 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
861 return 1;
864 tomnt = argv[optind];
866 if (fromfile) {
867 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
868 if (receive_fd < 0) {
869 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
870 return -errno;
874 ret = do_receive(&r, tomnt, receive_fd);
876 return ret;
879 static const char * const receive_cmd_group_usage[] = {
880 "btrfs receive <command> <args>",
881 NULL
884 const char * const cmd_receive_usage[] = {
885 "btrfs receive [-v] [-f <infile>] <mount>",
886 "Receive subvolumes from stdin.",
887 "Receives one or more subvolumes that were previously ",
888 "sent with btrfs send. The received subvolumes are stored",
889 "into <mount>.",
890 "btrfs receive will fail in case a receiving subvolume",
891 "already exists. It will also fail in case a previously",
892 "received subvolume was changed after it was received.",
893 "After receiving a subvolume, it is immediately set to",
894 "read only.\n",
895 "-v Enable verbose debug output. Each",
896 " occurrence of this option increases the",
897 " verbose level more.",
898 "-f <infile> By default, btrfs receive uses stdin",
899 " to receive the subvolumes. Use this",
900 " option to specify a file to use instead.",
901 NULL
904 const struct cmd_group receive_cmd_group = {
905 receive_cmd_group_usage, NULL, {
906 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
907 { 0, 0, 0, 0, 0 },
911 int cmd_receive(int argc, char **argv)
913 return do_cmd_receive(argc, argv);