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