2 * Copyright (C) 2013 SUSE. All rights reserved.
4 * This code is adapted from cmds-send.c and cmds-receive.c,
7 * Copyright (C) 2012 Alexander Block. All rights reserved.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License v2 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 021110-1307, USA.
31 #include <sys/types.h>
34 #include <sys/ioctl.h>
39 #include <asm/types.h>
40 #include <uuid/uuid.h>
43 * This should be compilable without the rest of the btrfs-progs
44 * source distribution.
46 #if BTRFS_FLAT_INCLUDES
47 #include "send-utils.h"
48 #include "send-stream.h"
50 #include <btrfs/send-utils.h>
51 #include <btrfs/send-stream.h>
52 #endif /* BTRFS_FLAT_INCLUDES */
55 struct btrfs_ioctl_send_args io_send
= {0, };
56 static char *subvol_path
;
57 static char *root_path
;
60 char *full_subvol_path
;
66 printf("send-test <btrfs root> <subvol>\n");
71 static int print_subvol(const char *path
, const u8
*uuid
, u64 ctransid
,
74 struct recv_args
*r
= user
;
75 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
77 r
->full_subvol_path
= path_cat(r
->root_path
, path
);
78 uuid_unparse(uuid
, uuid_str
);
80 printf("subvol\t%s\t%llu\t%s\n", uuid_str
,
81 (unsigned long long)ctransid
, r
->full_subvol_path
);
86 static int print_snapshot(const char *path
, const u8
*uuid
, u64 ctransid
,
87 const u8
*parent_uuid
, u64 parent_ctransid
,
90 struct recv_args
*r
= user
;
91 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
92 char parent_uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
94 r
->full_subvol_path
= path_cat(r
->root_path
, path
);
95 uuid_unparse(uuid
, uuid_str
);
96 uuid_unparse(parent_uuid
, parent_uuid_str
);
98 printf("snapshot\t%s\t%llu\t%s\t%llu\t%s\n", uuid_str
,
99 (unsigned long long)ctransid
, parent_uuid_str
,
100 (unsigned long long)parent_ctransid
, r
->full_subvol_path
);
105 static int print_mkfile(const char *path
, void *user
)
107 struct recv_args
*r
= user
;
108 char *full_path
= path_cat(r
->full_subvol_path
, path
);
110 printf("mkfile\t%s\n", full_path
);
116 static int print_mkdir(const char *path
, void *user
)
118 struct recv_args
*r
= user
;
119 char *full_path
= path_cat(r
->full_subvol_path
, path
);
121 printf("mkdir\t%s\n", full_path
);
127 static int print_mknod(const char *path
, u64 mode
, u64 dev
, void *user
)
129 struct recv_args
*r
= user
;
130 char *full_path
= path_cat(r
->full_subvol_path
, path
);
132 printf("mknod\t%llo\t0x%llx\t%s\n", (unsigned long long)mode
,
133 (unsigned long long)dev
, full_path
);
139 static int print_mkfifo(const char *path
, void *user
)
141 struct recv_args
*r
= user
;
142 char *full_path
= path_cat(r
->full_subvol_path
, path
);
144 printf("mkfifo\t%s\n", full_path
);
150 static int print_mksock(const char *path
, void *user
)
152 struct recv_args
*r
= user
;
153 char *full_path
= path_cat(r
->full_subvol_path
, path
);
155 printf("mksock\t%s\n", full_path
);
161 static int print_symlink(const char *path
, const char *lnk
, void *user
)
163 struct recv_args
*r
= user
;
164 char *full_path
= path_cat(r
->full_subvol_path
, path
);
166 printf("symlink\t%s\t%s\n", lnk
, full_path
);
172 static int print_rename(const char *from
, const char *to
, void *user
)
174 struct recv_args
*r
= user
;
175 char *full_from
= path_cat(r
->full_subvol_path
, from
);
176 char *full_to
= path_cat(r
->full_subvol_path
, to
);
178 printf("rename\t%s\t%s\n", from
, to
);
185 static int print_link(const char *path
, const char *lnk
, void *user
)
187 struct recv_args
*r
= user
;
188 char *full_path
= path_cat(r
->full_subvol_path
, path
);
190 printf("link\t%s\t%s\n", lnk
, full_path
);
196 static int print_unlink(const char *path
, void *user
)
198 struct recv_args
*r
= user
;
199 char *full_path
= path_cat(r
->full_subvol_path
, path
);
201 printf("unlink\t%s\n", full_path
);
207 static int print_rmdir(const char *path
, void *user
)
209 struct recv_args
*r
= user
;
210 char *full_path
= path_cat(r
->full_subvol_path
, path
);
212 printf("rmdir\t%s\n", full_path
);
218 static int print_write(const char *path
, const void *data
, u64 offset
,
221 struct recv_args
*r
= user
;
222 char *full_path
= path_cat(r
->full_subvol_path
, path
);
224 printf("write\t%llu\t%llu\t%s\n", (unsigned long long)offset
,
225 (unsigned long long)len
, full_path
);
231 static int print_clone(const char *path
, u64 offset
, u64 len
,
232 const u8
*clone_uuid
, u64 clone_ctransid
,
233 const char *clone_path
, u64 clone_offset
,
236 struct recv_args
*r
= user
;
237 char *full_path
= path_cat(r
->full_subvol_path
, path
);
239 printf("clone\t%s\t%s\n", full_path
, clone_path
);
245 static int print_set_xattr(const char *path
, const char *name
,
246 const void *data
, int len
, void *user
)
248 struct recv_args
*r
= user
;
249 char *full_path
= path_cat(r
->full_subvol_path
, path
);
251 printf("set_xattr\t%s\t%s\t%d\n", full_path
,
258 static int print_remove_xattr(const char *path
, const char *name
, void *user
)
260 struct recv_args
*r
= user
;
261 char *full_path
= path_cat(r
->full_subvol_path
, path
);
263 printf("remove_xattr\t%s\t%s\n", full_path
, name
);
269 static int print_truncate(const char *path
, u64 size
, void *user
)
271 struct recv_args
*r
= user
;
272 char *full_path
= path_cat(r
->full_subvol_path
, path
);
274 printf("truncate\t%llu\t%s\n", (unsigned long long)size
, full_path
);
280 static int print_chmod(const char *path
, u64 mode
, void *user
)
282 struct recv_args
*r
= user
;
283 char *full_path
= path_cat(r
->full_subvol_path
, path
);
285 printf("chmod\t%llo\t%s\n", (unsigned long long)mode
, full_path
);
291 static int print_chown(const char *path
, u64 uid
, u64 gid
, void *user
)
293 struct recv_args
*r
= user
;
294 char *full_path
= path_cat(r
->full_subvol_path
, path
);
296 printf("chown\t%llu\t%llu\t%s\n", (unsigned long long)uid
,
297 (unsigned long long)gid
, full_path
);
303 static int print_utimes(const char *path
, struct timespec
*at
,
304 struct timespec
*mt
, struct timespec
*ct
,
307 struct recv_args
*r
= user
;
308 char *full_path
= path_cat(r
->full_subvol_path
, path
);
310 printf("utimes\t%s\n", full_path
);
316 static int print_update_extent(const char *path
, u64 offset
, u64 len
,
319 struct recv_args
*r
= user
;
320 char *full_path
= path_cat(r
->full_subvol_path
, path
);
322 printf("update_extent\t%s\t%llu\t%llu\n", full_path
, offset
, len
);
328 static struct btrfs_send_ops send_ops_print
= {
329 .subvol
= print_subvol
,
330 .snapshot
= print_snapshot
,
331 .mkfile
= print_mkfile
,
332 .mkdir
= print_mkdir
,
333 .mknod
= print_mknod
,
334 .mkfifo
= print_mkfifo
,
335 .mksock
= print_mksock
,
336 .symlink
= print_symlink
,
337 .rename
= print_rename
,
339 .unlink
= print_unlink
,
340 .rmdir
= print_rmdir
,
341 .write
= print_write
,
342 .clone
= print_clone
,
343 .set_xattr
= print_set_xattr
,
344 .remove_xattr
= print_remove_xattr
,
345 .truncate
= print_truncate
,
346 .chmod
= print_chmod
,
347 .chown
= print_chown
,
348 .utimes
= print_utimes
,
349 .update_extent
= print_update_extent
,
352 static void *process_thread(void *arg_
)
357 ret
= btrfs_read_and_process_send_stream(pipefd
[0],
358 &send_ops_print
, arg_
, 0);
369 int main(int argc
, char **argv
)
374 pthread_attr_t t_attr
;
381 root_path
= realpath(argv
[1], NULL
);
387 subvol_path
= realpath(argv
[2], NULL
);
393 r
.full_subvol_path
= subvol_path
;
394 r
.root_path
= root_path
;
396 subvol_fd
= open(subvol_path
, O_RDONLY
|O_NOATIME
);
399 fprintf(stderr
, "ERROR: Subvolume open failed. %s\n",
404 ret
= pthread_attr_init(&t_attr
);
406 fprintf(stderr
, "ERROR: pthread init failed. %s\n",
414 fprintf(stderr
, "ERROR: pipe failed. %s\n", strerror(ret
));
418 ret
= pthread_create(&t_read
, &t_attr
, process_thread
, &r
);
421 fprintf(stderr
, "ERROR: pthread create failed. %s\n",
426 io_send
.send_fd
= pipefd
[1];
427 io_send
.clone_sources_count
= 0;
428 io_send
.clone_sources
= NULL
;
429 io_send
.parent_root
= 0;
430 io_send
.flags
= BTRFS_SEND_FLAG_NO_FILE_DATA
;
432 ret
= ioctl(subvol_fd
, BTRFS_IOC_SEND
, &io_send
);
435 fprintf(stderr
, "ERROR: send ioctl failed with %d: %s\n", ret
,
442 ret
= pthread_join(t_read
, &t_err
);
444 fprintf(stderr
, "ERROR: pthread_join failed: %s\n",
449 ret
= (long int)t_err
;
450 fprintf(stderr
, "ERROR: failed to process send stream, ret=%ld "
451 "(%s)\n", (long int)t_err
, strerror(ret
));
455 pthread_attr_destroy(&t_attr
);