btrfs-progs: fix csum root copy-n-paste error
[btrfs-progs-unstable/devel.git] / send-test.c
blob0e804a2431705f084fb224cb25d2a3b77379c4cc
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 #define _GNU_SOURCE
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <dirent.h>
29 #include <pthread.h>
30 #include <math.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 #include <libgen.h>
36 #include <mntent.h>
37 #include <limits.h>
38 #include <stdlib.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"
49 #else
50 #include <btrfs/send-utils.h>
51 #include <btrfs/send-stream.h>
52 #endif /* BTRFS_FLAT_INCLUDES */
54 static int pipefd[2];
55 struct btrfs_ioctl_send_args io_send = {0, };
56 static char *subvol_path;
57 static char *root_path;
59 struct recv_args {
60 char *full_subvol_path;
61 char *root_path;
64 void usage(int error)
66 printf("send-test <btrfs root> <subvol>\n");
67 if (error)
68 exit(error);
71 static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
72 void *user)
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);
83 return 0;
86 static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
87 const u8 *parent_uuid, u64 parent_ctransid,
88 void *user)
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);
102 return 0;
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);
112 free(full_path);
113 return 0;
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);
123 free(full_path);
124 return 0;
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);
135 free(full_path);
136 return 0;
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);
146 free(full_path);
147 return 0;
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);
157 free(full_path);
158 return 0;
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);
168 free(full_path);
169 return 0;
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);
180 free(full_from);
181 free(full_to);
182 return 0;
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);
192 free(full_path);
193 return 0;
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);
203 free(full_path);
204 return 0;
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);
214 free(full_path);
215 return 0;
218 static int print_write(const char *path, const void *data, u64 offset,
219 u64 len, void *user)
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);
227 free(full_path);
228 return 0;
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,
234 void *user)
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);
241 free(full_path);
242 return 0;
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,
252 name, len);
254 free(full_path);
255 return 0;
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);
265 free(full_path);
266 return 0;
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);
276 free(full_path);
277 return 0;
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);
287 free(full_path);
288 return 0;
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);
299 free(full_path);
300 return 0;
303 static int print_utimes(const char *path, struct timespec *at,
304 struct timespec *mt, struct timespec *ct,
305 void *user)
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);
312 free(full_path);
313 return 0;
316 static int print_update_extent(const char *path, u64 offset, u64 len,
317 void *user)
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);
324 free(full_path);
325 return 0;
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,
338 .link = print_link,
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_)
354 int ret;
356 while (1) {
357 ret = btrfs_read_and_process_send_stream(pipefd[0],
358 &send_ops_print, arg_, 0);
359 if (ret)
360 break;
363 if (ret > 0)
364 ret = 0;
366 return ERR_PTR(ret);
369 int main(int argc, char **argv)
371 int ret = 0;
372 int subvol_fd;
373 pthread_t t_read;
374 void *t_err = NULL;
375 struct recv_args r;
377 if (argc != 3)
378 usage(EINVAL);
380 root_path = realpath(argv[1], NULL);
381 if (!root_path) {
382 ret = errno;
383 usage(ret);
386 subvol_path = realpath(argv[2], NULL);
387 if (!subvol_path) {
388 ret = errno;
389 usage(ret);
392 r.full_subvol_path = subvol_path;
393 r.root_path = root_path;
395 subvol_fd = open(subvol_path, O_RDONLY|O_NOATIME);
396 if (subvol_fd < 0) {
397 ret = errno;
398 fprintf(stderr, "ERROR: Subvolume open failed. %s\n",
399 strerror(ret));
400 goto out;
403 ret = pipe(pipefd);
404 if (ret < 0) {
405 ret = errno;
406 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(ret));
407 goto out;
410 ret = pthread_create(&t_read, NULL, process_thread, &r);
411 if (ret < 0) {
412 ret = errno;
413 fprintf(stderr, "ERROR: pthread create failed. %s\n",
414 strerror(ret));
415 goto out;
418 io_send.send_fd = pipefd[1];
419 io_send.clone_sources_count = 0;
420 io_send.clone_sources = NULL;
421 io_send.parent_root = 0;
422 io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA;
424 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
425 if (ret) {
426 ret = errno;
427 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
428 strerror(ret));
429 goto out;
432 close(pipefd[1]);
434 ret = pthread_join(t_read, &t_err);
435 if (ret) {
436 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
437 strerror(ret));
438 goto out;
440 if (t_err) {
441 ret = (long int)t_err;
442 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
443 "(%s)\n", (long int)t_err, strerror(ret));
444 goto out;
447 out:
448 return !!ret;