btrfs-progs: pretty print key in extent_item
[btrfs-progs-unstable/devel.git] / cmds-receive.c
bloba8be6fa43db3eb22e5ca62d54e1068351acf675f
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 <unistd.h>
25 #include <stdint.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <math.h>
30 #include <ftw.h>
31 #include <wait.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/xattr.h>
39 #include <uuid/uuid.h>
41 #include "ctree.h"
42 #include "ioctl.h"
43 #include "commands.h"
44 #include "list.h"
46 #include "send.h"
47 #include "send-stream.h"
48 #include "send-utils.h"
50 static int g_verbose = 0;
52 struct btrfs_receive
54 int mnt_fd;
56 int write_fd;
57 char *write_path;
59 char *root_path;
60 char *full_subvol_path;
62 struct subvol_info *cur_subvol;
63 struct subvol_info *parent_subvol;
65 struct subvol_uuid_search sus;
68 static int finish_subvol(struct btrfs_receive *r)
70 int ret;
71 int subvol_fd = -1;
72 int info_fd = -1;
73 struct btrfs_ioctl_received_subvol_args rs_args;
74 char uuid_str[128];
75 u64 flags;
77 if (r->cur_subvol == NULL)
78 return 0;
80 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
81 O_RDONLY | O_NOATIME);
82 if (subvol_fd < 0) {
83 ret = -errno;
84 fprintf(stderr, "ERROR: open %s failed. %s\n",
85 r->cur_subvol->path, strerror(-ret));
86 goto out;
89 memset(&rs_args, 0, sizeof(rs_args));
90 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
91 rs_args.stransid = r->cur_subvol->stransid;
93 if (g_verbose >= 1) {
94 uuid_unparse((u8*)rs_args.uuid, uuid_str);
95 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
96 "stransid=%llu\n", uuid_str, rs_args.stransid);
99 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
100 if (ret < 0) {
101 ret = -errno;
102 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
103 strerror(-ret));
104 goto out;
106 r->cur_subvol->rtransid = rs_args.rtransid;
108 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
109 if (ret < 0) {
110 ret = -errno;
111 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
112 strerror(-ret));
113 goto out;
116 flags |= BTRFS_SUBVOL_RDONLY;
118 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
119 if (ret < 0) {
120 ret = -errno;
121 fprintf(stderr, "ERROR: failed to make subvolume read only. "
122 "%s\n", strerror(-ret));
123 goto out;
126 subvol_uuid_search_add(&r->sus, r->cur_subvol);
127 r->cur_subvol = NULL;
128 ret = 0;
130 out:
131 if (subvol_fd != -1)
132 close(subvol_fd);
133 if (info_fd != -1)
134 close(info_fd);
135 return ret;
138 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
139 void *user)
141 int ret;
142 struct btrfs_receive *r = user;
143 struct btrfs_ioctl_vol_args args_v1;
144 char uuid_str[128];
146 ret = finish_subvol(r);
147 if (ret < 0)
148 goto out;
150 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
151 r->parent_subvol = NULL;
153 r->cur_subvol->path = strdup(path);
154 r->full_subvol_path = path_cat(r->root_path, path);
156 fprintf(stderr, "At subvol %s\n", path);
158 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
159 r->cur_subvol->stransid = ctransid;
161 if (g_verbose) {
162 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
163 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
164 path, uuid_str,
165 r->cur_subvol->stransid);
168 memset(&args_v1, 0, sizeof(args_v1));
169 strcpy(args_v1.name, path);
170 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
171 if (ret < 0) {
172 ret = -errno;
173 fprintf(stderr, "ERROR: creating subvolume %s failed. "
174 "%s\n", path, strerror(-ret));
175 goto out;
178 out:
179 return ret;
182 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
183 const u8 *parent_uuid, u64 parent_ctransid,
184 void *user)
186 int ret;
187 struct btrfs_receive *r = user;
188 char uuid_str[128];
189 struct btrfs_ioctl_vol_args_v2 args_v2;
191 ret = finish_subvol(r);
192 if (ret < 0)
193 goto out;
195 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
196 r->parent_subvol = NULL;
198 r->cur_subvol->path = strdup(path);
199 r->full_subvol_path = path_cat(r->root_path, path);
201 fprintf(stderr, "At snapshot %s\n", path);
203 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
204 r->cur_subvol->stransid = ctransid;
206 if (g_verbose) {
207 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
208 fprintf(stderr, "receiving snapshot %s uuid=%s, "
209 "ctransid=%llu ", path, uuid_str,
210 r->cur_subvol->stransid);
211 uuid_unparse(parent_uuid, uuid_str);
212 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
213 uuid_str, parent_ctransid);
216 memset(&args_v2, 0, sizeof(args_v2));
217 strcpy(args_v2.name, path);
219 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
220 parent_ctransid, NULL, subvol_search_by_received_uuid);
221 if (!r->parent_subvol) {
222 ret = -ENOENT;
223 fprintf(stderr, "ERROR: could not find parent subvolume\n");
224 goto out;
227 /*if (rs_args.ctransid > rs_args.rtransid) {
228 if (!r->force) {
229 ret = -EINVAL;
230 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
231 goto out;
232 } else {
233 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
237 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
238 O_RDONLY | O_NOATIME);
239 if (args_v2.fd < 0) {
240 ret = -errno;
241 fprintf(stderr, "ERROR: open %s failed. %s\n",
242 r->parent_subvol->path, strerror(-ret));
243 goto out;
246 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
247 close(args_v2.fd);
248 if (ret < 0) {
249 ret = -errno;
250 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
251 "failed. %s\n", r->parent_subvol->path,
252 path, strerror(-ret));
253 goto out;
256 out:
257 return ret;
260 static int process_mkfile(const char *path, void *user)
262 int ret;
263 struct btrfs_receive *r = user;
264 char *full_path = path_cat(r->full_subvol_path, path);
266 if (g_verbose >= 1)
267 fprintf(stderr, "mkfile %s\n", path);
269 ret = creat(full_path, 0600);
270 if (ret < 0) {
271 ret = -errno;
272 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
273 strerror(-ret));
274 goto out;
276 close(ret);
277 ret = 0;
279 out:
280 free(full_path);
281 return ret;
284 static int process_mkdir(const char *path, void *user)
286 int ret;
287 struct btrfs_receive *r = user;
288 char *full_path = path_cat(r->full_subvol_path, path);
290 if (g_verbose >= 1)
291 fprintf(stderr, "mkdir %s\n", path);
293 ret = mkdir(full_path, 0700);
294 if (ret < 0) {
295 ret = -errno;
296 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
297 strerror(-ret));
300 free(full_path);
301 return ret;
304 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
306 int ret;
307 struct btrfs_receive *r = user;
308 char *full_path = path_cat(r->full_subvol_path, path);
310 if (g_verbose >= 1)
311 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
312 path, mode, dev);
314 ret = mknod(full_path, mode & S_IFMT, dev);
315 if (ret < 0) {
316 ret = -errno;
317 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
318 strerror(-ret));
321 free(full_path);
322 return ret;
325 static int process_mkfifo(const char *path, void *user)
327 int ret;
328 struct btrfs_receive *r = user;
329 char *full_path = path_cat(r->full_subvol_path, path);
331 if (g_verbose >= 1)
332 fprintf(stderr, "mkfifo %s\n", path);
334 ret = mkfifo(full_path, 0600);
335 if (ret < 0) {
336 ret = -errno;
337 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
338 strerror(-ret));
341 free(full_path);
342 return ret;
345 static int process_mksock(const char *path, void *user)
347 int ret;
348 struct btrfs_receive *r = user;
349 char *full_path = path_cat(r->full_subvol_path, path);
351 if (g_verbose >= 1)
352 fprintf(stderr, "mksock %s\n", path);
354 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
355 if (ret < 0) {
356 ret = -errno;
357 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
358 strerror(-ret));
361 free(full_path);
362 return ret;
365 static int process_symlink(const char *path, const char *lnk, void *user)
367 int ret;
368 struct btrfs_receive *r = user;
369 char *full_path = path_cat(r->full_subvol_path, path);
371 if (g_verbose >= 1)
372 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
374 ret = symlink(lnk, full_path);
375 if (ret < 0) {
376 ret = -errno;
377 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
378 lnk, strerror(-ret));
381 free(full_path);
382 return ret;
385 static int process_rename(const char *from, const char *to, void *user)
387 int ret;
388 struct btrfs_receive *r = user;
389 char *full_from = path_cat(r->full_subvol_path, from);
390 char *full_to = path_cat(r->full_subvol_path, to);
392 if (g_verbose >= 1)
393 fprintf(stderr, "rename %s -> %s\n", from, to);
395 ret = rename(full_from, full_to);
396 if (ret < 0) {
397 ret = -errno;
398 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
399 to, strerror(-ret));
402 free(full_from);
403 free(full_to);
404 return ret;
407 static int process_link(const char *path, const char *lnk, void *user)
409 int ret;
410 struct btrfs_receive *r = user;
411 char *full_path = path_cat(r->full_subvol_path, path);
412 char *full_link_path = path_cat(r->full_subvol_path, lnk);
414 if (g_verbose >= 1)
415 fprintf(stderr, "link %s -> %s\n", path, lnk);
417 ret = link(full_link_path, full_path);
418 if (ret < 0) {
419 ret = -errno;
420 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
421 lnk, strerror(-ret));
424 free(full_path);
425 free(full_link_path);
426 return ret;
430 static int process_unlink(const char *path, void *user)
432 int ret;
433 struct btrfs_receive *r = user;
434 char *full_path = path_cat(r->full_subvol_path, path);
436 if (g_verbose >= 1)
437 fprintf(stderr, "unlink %s\n", path);
439 ret = unlink(full_path);
440 if (ret < 0) {
441 ret = -errno;
442 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
443 strerror(-ret));
446 free(full_path);
447 return ret;
450 static int process_rmdir(const char *path, void *user)
452 int ret;
453 struct btrfs_receive *r = user;
454 char *full_path = path_cat(r->full_subvol_path, path);
456 if (g_verbose >= 1)
457 fprintf(stderr, "rmdir %s\n", path);
459 ret = rmdir(full_path);
460 if (ret < 0) {
461 ret = -errno;
462 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
463 strerror(-ret));
466 free(full_path);
467 return ret;
471 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
473 int ret = 0;
475 if (r->write_fd != -1) {
476 if (strcmp(r->write_path, path) == 0)
477 goto out;
478 close(r->write_fd);
479 r->write_fd = -1;
482 r->write_fd = open(path, O_RDWR);
483 if (r->write_fd < 0) {
484 ret = -errno;
485 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
486 strerror(-ret));
487 goto out;
489 free(r->write_path);
490 r->write_path = strdup(path);
492 out:
493 return ret;
496 static int close_inode_for_write(struct btrfs_receive *r)
498 int ret = 0;
500 if(r->write_fd == -1)
501 goto out;
503 close(r->write_fd);
504 r->write_fd = -1;
505 r->write_path[0] = 0;
507 out:
508 return ret;
511 static int process_write(const char *path, const void *data, u64 offset,
512 u64 len, void *user)
514 int ret = 0;
515 struct btrfs_receive *r = user;
516 char *full_path = path_cat(r->full_subvol_path, path);
517 u64 pos = 0;
518 int w;
520 ret = open_inode_for_write(r, full_path);
521 if (ret < 0)
522 goto out;
524 while (pos < len) {
525 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
526 offset + pos);
527 if (w < 0) {
528 ret = -errno;
529 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
530 path, strerror(-ret));
531 goto out;
533 pos += w;
536 out:
537 free(full_path);
538 return ret;
541 static int process_clone(const char *path, u64 offset, u64 len,
542 const u8 *clone_uuid, u64 clone_ctransid,
543 const char *clone_path, u64 clone_offset,
544 void *user)
546 int ret = 0;
547 struct btrfs_receive *r = user;
548 struct btrfs_ioctl_clone_range_args clone_args;
549 struct subvol_info *si = NULL;
550 char *full_path = path_cat(r->full_subvol_path, path);
551 char *subvol_path = NULL;
552 char *full_clone_path = NULL;
553 int clone_fd = -1;
555 ret = open_inode_for_write(r, full_path);
556 if (ret < 0)
557 goto out;
559 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
560 subvol_search_by_received_uuid);
561 if (!si) {
562 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
563 BTRFS_FSID_SIZE) == 0) {
564 /* TODO check generation of extent */
565 subvol_path = strdup(r->cur_subvol->path);
566 } else {
567 ret = -ENOENT;
568 fprintf(stderr, "ERROR: did not find source subvol.\n");
569 goto out;
571 } else {
572 /*if (rs_args.ctransid > rs_args.rtransid) {
573 if (!r->force) {
574 ret = -EINVAL;
575 fprintf(stderr, "ERROR: subvolume %s was "
576 "modified after it was "
577 "received.\n",
578 r->subvol_parent_name);
579 goto out;
580 } else {
581 fprintf(stderr, "WARNING: subvolume %s was "
582 "modified after it was "
583 "received.\n",
584 r->subvol_parent_name);
587 subvol_path = strdup(si->path);
590 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
592 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
593 if (clone_fd < 0) {
594 ret = -errno;
595 fprintf(stderr, "ERROR: failed to open %s. %s\n",
596 full_clone_path, strerror(-ret));
597 goto out;
600 clone_args.src_fd = clone_fd;
601 clone_args.src_offset = clone_offset;
602 clone_args.src_length = len;
603 clone_args.dest_offset = offset;
604 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
605 if (ret) {
606 ret = -errno;
607 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
608 path, strerror(-ret));
609 goto out;
612 out:
613 free(full_path);
614 free(full_clone_path);
615 free(subvol_path);
616 if (clone_fd != -1)
617 close(clone_fd);
618 return ret;
622 static int process_set_xattr(const char *path, const char *name,
623 const void *data, int len, void *user)
625 int ret = 0;
626 struct btrfs_receive *r = user;
627 char *full_path = path_cat(r->full_subvol_path, path);
629 if (g_verbose >= 1) {
630 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
631 "data=%.*s\n", path, name, len,
632 len, (char*)data);
635 ret = lsetxattr(full_path, name, data, len, 0);
636 if (ret < 0) {
637 ret = -errno;
638 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
639 path, name, len, (char*)data, strerror(-ret));
640 goto out;
643 out:
644 free(full_path);
645 return ret;
648 static int process_remove_xattr(const char *path, const char *name, void *user)
650 int ret = 0;
651 struct btrfs_receive *r = user;
652 char *full_path = path_cat(r->full_subvol_path, path);
654 if (g_verbose >= 1) {
655 fprintf(stderr, "remove_xattr %s - name=%s\n",
656 path, name);
659 ret = lremovexattr(full_path, name);
660 if (ret < 0) {
661 ret = -errno;
662 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
663 path, name, strerror(-ret));
664 goto out;
667 out:
668 free(full_path);
669 return ret;
672 static int process_truncate(const char *path, u64 size, void *user)
674 int ret = 0;
675 struct btrfs_receive *r = user;
676 char *full_path = path_cat(r->full_subvol_path, path);
678 if (g_verbose >= 1)
679 fprintf(stderr, "truncate %s size=%llu\n", path, size);
681 ret = truncate(full_path, size);
682 if (ret < 0) {
683 ret = -errno;
684 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
685 path, strerror(-ret));
686 goto out;
689 out:
690 free(full_path);
691 return ret;
694 static int process_chmod(const char *path, u64 mode, void *user)
696 int ret = 0;
697 struct btrfs_receive *r = user;
698 char *full_path = path_cat(r->full_subvol_path, path);
700 if (g_verbose >= 1)
701 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
703 ret = chmod(full_path, mode);
704 if (ret < 0) {
705 ret = -errno;
706 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
707 path, strerror(-ret));
708 goto out;
711 out:
712 free(full_path);
713 return ret;
716 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
718 int ret = 0;
719 struct btrfs_receive *r = user;
720 char *full_path = path_cat(r->full_subvol_path, path);
722 if (g_verbose >= 1)
723 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
724 uid, gid);
726 ret = chown(full_path, uid, gid);
727 if (ret < 0) {
728 ret = -errno;
729 fprintf(stderr, "ERROR: chown %s failed. %s\n",
730 path, strerror(-ret));
731 goto out;
734 out:
735 free(full_path);
736 return ret;
739 static int process_utimes(const char *path, struct timespec *at,
740 struct timespec *mt, struct timespec *ct,
741 void *user)
743 int ret = 0;
744 struct btrfs_receive *r = user;
745 char *full_path = path_cat(r->full_subvol_path, path);
746 struct timespec tv[2];
748 if (g_verbose >= 1)
749 fprintf(stderr, "utimes %s\n", path);
751 tv[0] = *at;
752 tv[1] = *mt;
753 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
754 if (ret < 0) {
755 ret = -errno;
756 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
757 path, strerror(-ret));
758 goto out;
761 out:
762 free(full_path);
763 return ret;
767 struct btrfs_send_ops send_ops = {
768 .subvol = process_subvol,
769 .snapshot = process_snapshot,
770 .mkfile = process_mkfile,
771 .mkdir = process_mkdir,
772 .mknod = process_mknod,
773 .mkfifo = process_mkfifo,
774 .mksock = process_mksock,
775 .symlink = process_symlink,
776 .rename = process_rename,
777 .link = process_link,
778 .unlink = process_unlink,
779 .rmdir = process_rmdir,
780 .write = process_write,
781 .clone = process_clone,
782 .set_xattr = process_set_xattr,
783 .remove_xattr = process_remove_xattr,
784 .truncate = process_truncate,
785 .chmod = process_chmod,
786 .chown = process_chown,
787 .utimes = process_utimes,
790 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
792 int ret;
793 int end = 0;
795 r->root_path = strdup(tomnt);
796 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
797 if (r->mnt_fd < 0) {
798 ret = -errno;
799 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
800 strerror(-ret));
801 goto out;
804 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
805 if (ret < 0)
806 return ret;
808 r->write_fd = -1;
810 while (!end) {
811 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
812 if (ret < 0)
813 goto out;
814 if (ret)
815 end = 1;
817 ret = close_inode_for_write(r);
818 if (ret < 0)
819 goto out;
820 ret = finish_subvol(r);
821 if (ret < 0)
822 goto out;
824 ret = 0;
826 out:
827 return ret;
830 static int do_cmd_receive(int argc, char **argv)
832 int c;
833 char *tomnt = NULL;
834 char *fromfile = NULL;
835 struct btrfs_receive r;
836 int receive_fd = fileno(stdin);
838 int ret;
840 memset(&r, 0, sizeof(r));
842 while ((c = getopt(argc, argv, "vf:")) != -1) {
843 switch (c) {
844 case 'v':
845 g_verbose++;
846 break;
847 case 'f':
848 fromfile = optarg;
849 break;
850 case '?':
851 default:
852 fprintf(stderr, "ERROR: receive args invalid.\n");
853 return 1;
857 if (optind + 1 != argc) {
858 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
859 return 1;
862 tomnt = argv[optind];
864 if (fromfile) {
865 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
866 if (receive_fd < 0) {
867 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
868 return -errno;
872 ret = do_receive(&r, tomnt, receive_fd);
874 return ret;
877 static const char * const receive_cmd_group_usage[] = {
878 "btrfs receive <command> <args>",
879 NULL
882 static const char * const cmd_receive_usage[] = {
883 "btrfs receive [-v] [-i <infile>] <mount>",
884 "Receive subvolumes from stdin.",
885 "Receives one or more subvolumes that were previously ",
886 "sent with btrfs send. The received subvolumes are stored",
887 "into <mount>.",
888 "btrfs receive will fail in case a receiving subvolume",
889 "already exists. It will also fail in case a previously",
890 "received subvolume was changed after it was received.",
891 "After receiving a subvolume, it is immediately set to",
892 "read only.\n",
893 "-v Enable verbose debug output. Each",
894 " occurrency of this option increases the",
895 " verbose level more.",
896 "-f <infile> By default, btrfs receive uses stdin",
897 " to receive the subvolumes. Use this",
898 " option to specify a file to use instead.",
899 NULL
902 const struct cmd_group receive_cmd_group = {
903 receive_cmd_group_usage, NULL, {
904 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
905 { 0, 0, 0, 0, 0 },
909 int cmd_receive(int argc, char **argv)
911 return do_cmd_receive(argc, argv);