btrfs-progs: output the correct path when fi-usage failed
[platform/upstream/btrfs-progs.git] / send-test.c
1 /*
2  * Copyright (C) 2013 SUSE.  All rights reserved.
3  *
4  * This code is adapted from cmds-send.c and cmds-receive.c,
5  * Both of which are:
6  *
7  * Copyright (C) 2012 Alexander Block.  All rights reserved.
8  *
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.
12  *
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.
17  *
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.
22  */
23
24 #define _GNU_SOURCE
25
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>
41
42 /*
43  * This should be compilable without the rest of the btrfs-progs
44  * source distribution.
45  */
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 */
53
54 static int pipefd[2];
55 struct btrfs_ioctl_send_args io_send = {0, };
56 static char *subvol_path;
57 static char *root_path;
58
59 struct recv_args {
60         char *full_subvol_path;
61         char *root_path;
62 };
63
64 void usage(int error)
65 {
66         printf("send-test <btrfs root> <subvol>\n");
67         if (error)
68                 exit(error);
69 }
70
71 static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
72                         void *user)
73 {
74         struct recv_args *r = user;
75         char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
76
77         r->full_subvol_path = path_cat(r->root_path, path);
78         uuid_unparse(uuid, uuid_str);
79
80         printf("subvol\t%s\t%llu\t%s\n", uuid_str,
81                (unsigned long long)ctransid, r->full_subvol_path);
82
83         return 0;
84 }
85
86 static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
87                           const u8 *parent_uuid, u64 parent_ctransid,
88                           void *user)
89 {
90         struct recv_args *r = user;
91         char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
92         char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
93
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);
97
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);
101
102         return 0;
103 }
104
105 static int print_mkfile(const char *path, void *user)
106 {
107         struct recv_args *r = user;
108         char *full_path = path_cat(r->full_subvol_path, path);
109
110         printf("mkfile\t%s\n", full_path);
111
112         free(full_path);
113         return 0;
114 }
115
116 static int print_mkdir(const char *path, void *user)
117 {
118         struct recv_args *r = user;
119         char *full_path = path_cat(r->full_subvol_path, path);
120
121         printf("mkdir\t%s\n", full_path);
122
123         free(full_path);
124         return 0;
125 }
126
127 static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
128 {
129         struct recv_args *r = user;
130         char *full_path = path_cat(r->full_subvol_path, path);
131
132         printf("mknod\t%llo\t0x%llx\t%s\n", (unsigned long long)mode,
133                (unsigned long long)dev, full_path);
134
135         free(full_path);
136         return 0;
137 }
138
139 static int print_mkfifo(const char *path, void *user)
140 {
141         struct recv_args *r = user;
142         char *full_path = path_cat(r->full_subvol_path, path);
143
144         printf("mkfifo\t%s\n", full_path);
145
146         free(full_path);
147         return 0;
148 }
149
150 static int print_mksock(const char *path, void *user)
151 {
152         struct recv_args *r = user;
153         char *full_path = path_cat(r->full_subvol_path, path);
154
155         printf("mksock\t%s\n", full_path);
156
157         free(full_path);
158         return 0;
159 }
160
161 static int print_symlink(const char *path, const char *lnk, void *user)
162 {
163         struct recv_args *r = user;
164         char *full_path = path_cat(r->full_subvol_path, path);
165
166         printf("symlink\t%s\t%s\n", lnk, full_path);
167
168         free(full_path);
169         return 0;
170 }
171
172 static int print_rename(const char *from, const char *to, void *user)
173 {
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);
177
178         printf("rename\t%s\t%s\n", from, to);
179
180         free(full_from);
181         free(full_to);
182         return 0;
183 }
184
185 static int print_link(const char *path, const char *lnk, void *user)
186 {
187         struct recv_args *r = user;
188         char *full_path = path_cat(r->full_subvol_path, path);
189
190         printf("link\t%s\t%s\n", lnk, full_path);
191
192         free(full_path);
193         return 0;
194 }
195
196 static int print_unlink(const char *path, void *user)
197 {
198         struct recv_args *r = user;
199         char *full_path = path_cat(r->full_subvol_path, path);
200
201         printf("unlink\t%s\n", full_path);
202
203         free(full_path);
204         return 0;
205 }
206
207 static int print_rmdir(const char *path, void *user)
208 {
209         struct recv_args *r = user;
210         char *full_path = path_cat(r->full_subvol_path, path);
211
212         printf("rmdir\t%s\n", full_path);
213
214         free(full_path);
215         return 0;
216 }
217
218 static int print_write(const char *path, const void *data, u64 offset,
219                        u64 len, void *user)
220 {
221         struct recv_args *r = user;
222         char *full_path = path_cat(r->full_subvol_path, path);
223
224         printf("write\t%llu\t%llu\t%s\n", (unsigned long long)offset,
225                (unsigned long long)len, full_path);
226
227         free(full_path);
228         return 0;
229 }
230
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)
235 {
236         struct recv_args *r = user;
237         char *full_path = path_cat(r->full_subvol_path, path);
238
239         printf("clone\t%s\t%s\n", full_path, clone_path);
240
241         free(full_path);
242         return 0;
243 }
244
245 static int print_set_xattr(const char *path, const char *name,
246                            const void *data, int len, void *user)
247 {
248         struct recv_args *r = user;
249         char *full_path = path_cat(r->full_subvol_path, path);
250
251         printf("set_xattr\t%s\t%s\t%d\n", full_path,
252                name, len);
253
254         free(full_path);
255         return 0;
256 }
257
258 static int print_remove_xattr(const char *path, const char *name, void *user)
259 {
260         struct recv_args *r = user;
261         char *full_path = path_cat(r->full_subvol_path, path);
262
263         printf("remove_xattr\t%s\t%s\n", full_path, name);
264
265         free(full_path);
266         return 0;
267 }
268
269 static int print_truncate(const char *path, u64 size, void *user)
270 {
271         struct recv_args *r = user;
272         char *full_path = path_cat(r->full_subvol_path, path);
273
274         printf("truncate\t%llu\t%s\n", (unsigned long long)size, full_path);
275
276         free(full_path);
277         return 0;
278 }
279
280 static int print_chmod(const char *path, u64 mode, void *user)
281 {
282         struct recv_args *r = user;
283         char *full_path = path_cat(r->full_subvol_path, path);
284
285         printf("chmod\t%llo\t%s\n", (unsigned long long)mode, full_path);
286
287         free(full_path);
288         return 0;
289 }
290
291 static int print_chown(const char *path, u64 uid, u64 gid, void *user)
292 {
293         struct recv_args *r = user;
294         char *full_path = path_cat(r->full_subvol_path, path);
295
296         printf("chown\t%llu\t%llu\t%s\n", (unsigned long long)uid,
297                (unsigned long long)gid, full_path);
298
299         free(full_path);
300         return 0;
301 }
302
303 static int print_utimes(const char *path, struct timespec *at,
304                         struct timespec *mt, struct timespec *ct,
305                         void *user)
306 {
307         struct recv_args *r = user;
308         char *full_path = path_cat(r->full_subvol_path, path);
309
310         printf("utimes\t%s\n", full_path);
311
312         free(full_path);
313         return 0;
314 }
315
316 static int print_update_extent(const char *path, u64 offset, u64 len,
317                                void *user)
318 {
319         struct recv_args *r = user;
320         char *full_path = path_cat(r->full_subvol_path, path);
321
322         printf("update_extent\t%s\t%llu\t%llu\n", full_path, offset, len);
323
324         free(full_path);
325         return 0;
326 }
327
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,
350 };
351
352 static void *process_thread(void *arg_)
353 {
354         int ret;
355
356         while (1) {
357                 ret = btrfs_read_and_process_send_stream(pipefd[0],
358                                                          &send_ops_print, arg_, 0);
359                 if (ret)
360                         break;
361         }
362
363         if (ret > 0)
364                 ret = 0;
365
366         return ERR_PTR(ret);
367 }
368
369 int main(int argc, char **argv)
370 {
371         int ret = 0;
372         int subvol_fd;
373         pthread_t t_read;
374         void *t_err = NULL;
375         struct recv_args r;
376
377         if (argc != 3)
378                 usage(EINVAL);
379
380         root_path = realpath(argv[1], NULL);
381         if (!root_path) {
382                 ret = errno;
383                 usage(ret);
384         }
385
386         subvol_path = realpath(argv[2], NULL);
387         if (!subvol_path) {
388                 ret = errno;
389                 usage(ret);
390         }
391
392         r.full_subvol_path = subvol_path;
393         r.root_path = root_path;
394
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;
401         }
402
403         ret = pipe(pipefd);
404         if (ret < 0) {
405                 ret = errno;
406                 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(ret));
407                 goto out;
408         }
409
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;
416         }
417
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;
423
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;
430         }
431
432         close(pipefd[1]);
433
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;
439         }
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;
445         }
446
447 out:
448         return !!ret;
449 }