btrfs-progs: btrfs: Add missing btrfs_close_all_devices for btrfs command
[btrfs-progs-unstable/devel.git] / send-test.c
blobaf8229e33e9c4f93b2e4cc1ff026cae6bf10b07e
1 /*
2 * Copyright (C) 2013 SUSE. All rights reserved.
4 * This code is adapted from cmds-send.c and cmds-receive.c,
5 * Both of which are:
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.
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <dirent.h>
27 #include <pthread.h>
28 #include <math.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <libgen.h>
34 #include <mntent.h>
35 #include <limits.h>
36 #include <stdlib.h>
37 #include <asm/types.h>
38 #include <uuid/uuid.h>
41 * This should be compilable without the rest of the btrfs-progs
42 * source distribution.
44 #if BTRFS_FLAT_INCLUDES
45 #include "send-utils.h"
46 #include "send-stream.h"
47 #else
48 #include <btrfs/send-utils.h>
49 #include <btrfs/send-stream.h>
50 #endif /* BTRFS_FLAT_INCLUDES */
52 static int pipefd[2];
53 struct btrfs_ioctl_send_args io_send = {0, };
54 static char *subvol_path;
55 static char *root_path;
57 struct recv_args {
58 char *full_subvol_path;
59 char *root_path;
62 void usage(int error)
64 printf("send-test <btrfs root> <subvol>\n");
65 if (error)
66 exit(error);
69 static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
70 void *user)
72 struct recv_args *r = user;
73 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
75 r->full_subvol_path = path_cat(r->root_path, path);
76 uuid_unparse(uuid, uuid_str);
78 printf("subvol\t%s\t%llu\t%s\n", uuid_str,
79 (unsigned long long)ctransid, r->full_subvol_path);
81 return 0;
84 static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
85 const u8 *parent_uuid, u64 parent_ctransid,
86 void *user)
88 struct recv_args *r = user;
89 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
90 char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
92 r->full_subvol_path = path_cat(r->root_path, path);
93 uuid_unparse(uuid, uuid_str);
94 uuid_unparse(parent_uuid, parent_uuid_str);
96 printf("snapshot\t%s\t%llu\t%s\t%llu\t%s\n", uuid_str,
97 (unsigned long long)ctransid, parent_uuid_str,
98 (unsigned long long)parent_ctransid, r->full_subvol_path);
100 return 0;
103 static int print_mkfile(const char *path, void *user)
105 struct recv_args *r = user;
106 char *full_path = path_cat(r->full_subvol_path, path);
108 printf("mkfile\t%s\n", full_path);
110 free(full_path);
111 return 0;
114 static int print_mkdir(const char *path, void *user)
116 struct recv_args *r = user;
117 char *full_path = path_cat(r->full_subvol_path, path);
119 printf("mkdir\t%s\n", full_path);
121 free(full_path);
122 return 0;
125 static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
127 struct recv_args *r = user;
128 char *full_path = path_cat(r->full_subvol_path, path);
130 printf("mknod\t%llo\t0x%llx\t%s\n", (unsigned long long)mode,
131 (unsigned long long)dev, full_path);
133 free(full_path);
134 return 0;
137 static int print_mkfifo(const char *path, void *user)
139 struct recv_args *r = user;
140 char *full_path = path_cat(r->full_subvol_path, path);
142 printf("mkfifo\t%s\n", full_path);
144 free(full_path);
145 return 0;
148 static int print_mksock(const char *path, void *user)
150 struct recv_args *r = user;
151 char *full_path = path_cat(r->full_subvol_path, path);
153 printf("mksock\t%s\n", full_path);
155 free(full_path);
156 return 0;
159 static int print_symlink(const char *path, const char *lnk, void *user)
161 struct recv_args *r = user;
162 char *full_path = path_cat(r->full_subvol_path, path);
164 printf("symlink\t%s\t%s\n", lnk, full_path);
166 free(full_path);
167 return 0;
170 static int print_rename(const char *from, const char *to, void *user)
172 struct recv_args *r = user;
173 char *full_from = path_cat(r->full_subvol_path, from);
174 char *full_to = path_cat(r->full_subvol_path, to);
176 printf("rename\t%s\t%s\n", from, to);
178 free(full_from);
179 free(full_to);
180 return 0;
183 static int print_link(const char *path, const char *lnk, void *user)
185 struct recv_args *r = user;
186 char *full_path = path_cat(r->full_subvol_path, path);
188 printf("link\t%s\t%s\n", lnk, full_path);
190 free(full_path);
191 return 0;
194 static int print_unlink(const char *path, void *user)
196 struct recv_args *r = user;
197 char *full_path = path_cat(r->full_subvol_path, path);
199 printf("unlink\t%s\n", full_path);
201 free(full_path);
202 return 0;
205 static int print_rmdir(const char *path, void *user)
207 struct recv_args *r = user;
208 char *full_path = path_cat(r->full_subvol_path, path);
210 printf("rmdir\t%s\n", full_path);
212 free(full_path);
213 return 0;
216 static int print_write(const char *path, const void *data, u64 offset,
217 u64 len, void *user)
219 struct recv_args *r = user;
220 char *full_path = path_cat(r->full_subvol_path, path);
222 printf("write\t%llu\t%llu\t%s\n", (unsigned long long)offset,
223 (unsigned long long)len, full_path);
225 free(full_path);
226 return 0;
229 static int print_clone(const char *path, u64 offset, u64 len,
230 const u8 *clone_uuid, u64 clone_ctransid,
231 const char *clone_path, u64 clone_offset,
232 void *user)
234 struct recv_args *r = user;
235 char *full_path = path_cat(r->full_subvol_path, path);
237 printf("clone\t%s\t%s\n", full_path, clone_path);
239 free(full_path);
240 return 0;
243 static int print_set_xattr(const char *path, const char *name,
244 const void *data, int len, void *user)
246 struct recv_args *r = user;
247 char *full_path = path_cat(r->full_subvol_path, path);
249 printf("set_xattr\t%s\t%s\t%d\n", full_path,
250 name, len);
252 free(full_path);
253 return 0;
256 static int print_remove_xattr(const char *path, const char *name, void *user)
258 struct recv_args *r = user;
259 char *full_path = path_cat(r->full_subvol_path, path);
261 printf("remove_xattr\t%s\t%s\n", full_path, name);
263 free(full_path);
264 return 0;
267 static int print_truncate(const char *path, u64 size, void *user)
269 struct recv_args *r = user;
270 char *full_path = path_cat(r->full_subvol_path, path);
272 printf("truncate\t%llu\t%s\n", (unsigned long long)size, full_path);
274 free(full_path);
275 return 0;
278 static int print_chmod(const char *path, u64 mode, void *user)
280 struct recv_args *r = user;
281 char *full_path = path_cat(r->full_subvol_path, path);
283 printf("chmod\t%llo\t%s\n", (unsigned long long)mode, full_path);
285 free(full_path);
286 return 0;
289 static int print_chown(const char *path, u64 uid, u64 gid, void *user)
291 struct recv_args *r = user;
292 char *full_path = path_cat(r->full_subvol_path, path);
294 printf("chown\t%llu\t%llu\t%s\n", (unsigned long long)uid,
295 (unsigned long long)gid, full_path);
297 free(full_path);
298 return 0;
301 static int print_utimes(const char *path, struct timespec *at,
302 struct timespec *mt, struct timespec *ct,
303 void *user)
305 struct recv_args *r = user;
306 char *full_path = path_cat(r->full_subvol_path, path);
308 printf("utimes\t%s\n", full_path);
310 free(full_path);
311 return 0;
314 static int print_update_extent(const char *path, u64 offset, u64 len,
315 void *user)
317 struct recv_args *r = user;
318 char *full_path = path_cat(r->full_subvol_path, path);
320 printf("update_extent\t%s\t%llu\t%llu\n", full_path, offset, len);
322 free(full_path);
323 return 0;
326 static struct btrfs_send_ops send_ops_print = {
327 .subvol = print_subvol,
328 .snapshot = print_snapshot,
329 .mkfile = print_mkfile,
330 .mkdir = print_mkdir,
331 .mknod = print_mknod,
332 .mkfifo = print_mkfifo,
333 .mksock = print_mksock,
334 .symlink = print_symlink,
335 .rename = print_rename,
336 .link = print_link,
337 .unlink = print_unlink,
338 .rmdir = print_rmdir,
339 .write = print_write,
340 .clone = print_clone,
341 .set_xattr = print_set_xattr,
342 .remove_xattr = print_remove_xattr,
343 .truncate = print_truncate,
344 .chmod = print_chmod,
345 .chown = print_chown,
346 .utimes = print_utimes,
347 .update_extent = print_update_extent,
350 static void *process_thread(void *arg_)
352 int ret;
354 while (1) {
355 ret = btrfs_read_and_process_send_stream(pipefd[0],
356 &send_ops_print, arg_, 0);
357 if (ret)
358 break;
361 if (ret > 0)
362 ret = 0;
364 return ERR_PTR(ret);
367 int main(int argc, char **argv)
369 int ret = 0;
370 int subvol_fd;
371 pthread_t t_read;
372 void *t_err = NULL;
373 struct recv_args r;
375 if (argc != 3)
376 usage(EINVAL);
378 root_path = realpath(argv[1], NULL);
379 if (!root_path) {
380 ret = errno;
381 usage(ret);
384 subvol_path = realpath(argv[2], NULL);
385 if (!subvol_path) {
386 ret = errno;
387 usage(ret);
390 r.full_subvol_path = subvol_path;
391 r.root_path = root_path;
393 subvol_fd = open(subvol_path, O_RDONLY|O_NOATIME);
394 if (subvol_fd < 0) {
395 ret = errno;
396 fprintf(stderr, "ERROR: Subvolume open failed. %s\n",
397 strerror(ret));
398 goto out;
401 ret = pipe(pipefd);
402 if (ret < 0) {
403 ret = errno;
404 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(ret));
405 goto out;
408 ret = pthread_create(&t_read, NULL, process_thread, &r);
409 if (ret < 0) {
410 ret = errno;
411 fprintf(stderr, "ERROR: pthread create failed. %s\n",
412 strerror(ret));
413 goto out;
416 io_send.send_fd = pipefd[1];
417 io_send.clone_sources_count = 0;
418 io_send.clone_sources = NULL;
419 io_send.parent_root = 0;
420 io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA;
422 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
423 if (ret) {
424 ret = errno;
425 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
426 strerror(ret));
427 goto out;
430 close(pipefd[1]);
432 ret = pthread_join(t_read, &t_err);
433 if (ret) {
434 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
435 strerror(ret));
436 goto out;
438 if (t_err) {
439 ret = (long int)t_err;
440 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
441 "(%s)\n", (long int)t_err, strerror(ret));
442 goto out;
445 out:
446 return !!ret;