2 * Copyright (C) 2016 Fujitsu. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program.
22 #include <sys/types.h>
25 #include <sys/ioctl.h>
32 #include <asm/types.h>
33 #include <uuid/uuid.h>
36 #include "send-utils.h"
37 #include "send-stream.h"
38 #include "send-dump.h"
40 #define PATH_CAT_OR_RET(function_name, outpath, path1, path2, ret) \
42 ret = path_cat_out(outpath, path1, path2); \
44 error("%s: path invalid: %s\n", function_name, path2); \
50 * Print path and escape chaacters (in a C way) that could break the line.
51 * Returns the length of the escaped characters. Unprintable characters are
54 static int print_path_escaped(const char *path
)
57 size_t path_len
= strlen(path
);
60 for (i
= 0; i
< path_len
; i
++) {
65 case '\a': putchar('\\'); putchar('a'); len
++; break;
66 case '\b': putchar('\\'); putchar('b'); len
++; break;
67 case '\e': putchar('\\'); putchar('e'); len
++; break;
68 case '\f': putchar('\\'); putchar('f'); len
++; break;
69 case '\n': putchar('\\'); putchar('n'); len
++; break;
70 case '\r': putchar('\\'); putchar('r'); len
++; break;
71 case '\t': putchar('\\'); putchar('t'); len
++; break;
72 case '\v': putchar('\\'); putchar('v'); len
++; break;
73 case ' ': putchar('\\'); putchar(' '); len
++; break;
74 case '\\': putchar('\\'); putchar('\\'); len
++; break;
78 '0' + ((c
& 0300) >> 6),
79 '0' + ((c
& 070) >> 3),
91 * Underlying PRINT_DUMP, the only difference is how we handle
94 __attribute__ ((format (printf
, 5, 6)))
95 static int __print_dump(int subvol
, void *user
, const char *path
,
96 const char *title
, const char *fmt
, ...)
98 struct btrfs_dump_send_args
*r
= user
;
99 char full_path
[PATH_MAX
] = {0};
105 PATH_CAT_OR_RET(title
, r
->full_subvol_path
, r
->root_path
, path
, ret
);
106 out_path
= r
->full_subvol_path
;
108 PATH_CAT_OR_RET(title
, full_path
, r
->full_subvol_path
, path
, ret
);
109 out_path
= full_path
;
113 printf("%-16s", title
);
114 ret
= print_path_escaped(out_path
);
119 /* Short paths are aligned to 32 chars; longer paths get a single space */
122 } while (++ret
< 32);
124 /* Operation specified ones */
131 /* For subvolume/snapshot operation only */
132 #define PRINT_DUMP_SUBVOL(user, path, title, fmt, ...) \
133 __print_dump(1, user, path, title, fmt, ##__VA_ARGS__)
135 /* For other operations */
136 #define PRINT_DUMP(user, path, title, fmt, ...) \
137 __print_dump(0, user, path, title, fmt, ##__VA_ARGS__)
139 static int print_subvol(const char *path
, const u8
*uuid
, u64 ctransid
,
142 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
144 uuid_unparse(uuid
, uuid_str
);
146 return PRINT_DUMP_SUBVOL(user
, path
, "subvol", "uuid=%s transid=%llu",
150 static int print_snapshot(const char *path
, const u8
*uuid
, u64 ctransid
,
151 const u8
*parent_uuid
, u64 parent_ctransid
,
154 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
155 char parent_uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
158 uuid_unparse(uuid
, uuid_str
);
159 uuid_unparse(parent_uuid
, parent_uuid_str
);
161 ret
= PRINT_DUMP_SUBVOL(user
, path
, "snapshot",
162 "uuid=%s transid=%llu parent_uuid=%s parent_transid=%llu",
163 uuid_str
, ctransid
, parent_uuid_str
,
168 static int print_mkfile(const char *path
, void *user
)
170 return PRINT_DUMP(user
, path
, "mkfile", NULL
);
173 static int print_mkdir(const char *path
, void *user
)
175 return PRINT_DUMP(user
, path
, "mkdir", NULL
);
178 static int print_mknod(const char *path
, u64 mode
, u64 dev
, void *user
)
180 return PRINT_DUMP(user
, path
, "mknod", "mode=%llo dev=0x%llx", mode
,
184 static int print_mkfifo(const char *path
, void *user
)
186 return PRINT_DUMP(user
, path
, "mkfifo", NULL
);
189 static int print_mksock(const char *path
, void *user
)
191 return PRINT_DUMP(user
, path
, "mksock", NULL
);
194 static int print_symlink(const char *path
, const char *lnk
, void *user
)
196 return PRINT_DUMP(user
, path
, "symlink", "dest=%s", lnk
);
199 static int print_rename(const char *from
, const char *to
, void *user
)
201 struct btrfs_dump_send_args
*r
= user
;
202 char full_to
[PATH_MAX
];
205 PATH_CAT_OR_RET("rename", full_to
, r
->full_subvol_path
, to
, ret
);
206 return PRINT_DUMP(user
, from
, "rename", "dest=%s", full_to
);
209 static int print_link(const char *path
, const char *lnk
, void *user
)
211 return PRINT_DUMP(user
, path
, "link", "dest=%s", lnk
);
214 static int print_unlink(const char *path
, void *user
)
216 return PRINT_DUMP(user
, path
, "unlink", NULL
);
219 static int print_rmdir(const char *path
, void *user
)
221 return PRINT_DUMP(user
, path
, "rmdir", NULL
);
224 static int print_write(const char *path
, const void *data
, u64 offset
,
227 return PRINT_DUMP(user
, path
, "write", "offset=%llu len=%llu",
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 btrfs_dump_send_args
*r
= user
;
237 char full_path
[PATH_MAX
];
240 PATH_CAT_OR_RET("clone", full_path
, r
->full_subvol_path
, clone_path
,
242 return PRINT_DUMP(user
, path
, "clone",
243 "offset=%llu len=%llu from=%s clone_offset=%llu",
244 offset
, len
, full_path
, clone_offset
);
247 static int print_set_xattr(const char *path
, const char *name
,
248 const void *data
, int len
, void *user
)
250 return PRINT_DUMP(user
, path
, "set_xattr", "name=%s data=%.*s len=%d",
251 name
, len
, (char *)data
, len
);
254 static int print_remove_xattr(const char *path
, const char *name
, void *user
)
257 return PRINT_DUMP(user
, path
, "remove_xattr", "name=%s", name
);
260 static int print_truncate(const char *path
, u64 size
, void *user
)
262 return PRINT_DUMP(user
, path
, "truncate", "size=%llu", size
);
265 static int print_chmod(const char *path
, u64 mode
, void *user
)
267 return PRINT_DUMP(user
, path
, "chmod", "mode=%llo", mode
);
270 static int print_chown(const char *path
, u64 uid
, u64 gid
, void *user
)
272 return PRINT_DUMP(user
, path
, "chown", "gid=%llu uid=%llu", gid
, uid
);
275 static int sprintf_timespec(struct timespec
*ts
, char *dest
, int max_size
)
280 if (!localtime_r(&ts
->tv_sec
, &tm
)) {
281 error("failed to convert time %lld.%.9ld to local time",
282 (long long)ts
->tv_sec
, ts
->tv_nsec
);
285 ret
= strftime(dest
, max_size
, "%FT%T%z", &tm
);
288 "time %lld.%ld is too long to convert into readable string",
289 (long long)ts
->tv_sec
, ts
->tv_nsec
);
295 #define TIME_STRING_MAX 64
296 static int print_utimes(const char *path
, struct timespec
*at
,
297 struct timespec
*mt
, struct timespec
*ct
,
300 char at_str
[TIME_STRING_MAX
];
301 char mt_str
[TIME_STRING_MAX
];
302 char ct_str
[TIME_STRING_MAX
];
304 if (sprintf_timespec(at
, at_str
, TIME_STRING_MAX
- 1) < 0 ||
305 sprintf_timespec(mt
, mt_str
, TIME_STRING_MAX
- 1) < 0 ||
306 sprintf_timespec(ct
, ct_str
, TIME_STRING_MAX
- 1) < 0)
308 return PRINT_DUMP(user
, path
, "utimes", "atime=%s mtime=%s ctime=%s",
309 at_str
, mt_str
, ct_str
);
312 static int print_update_extent(const char *path
, u64 offset
, u64 len
,
315 return PRINT_DUMP(user
, path
, "update_extent", "offset=%llu len=%llu",
319 struct btrfs_send_ops btrfs_print_send_ops
= {
320 .subvol
= print_subvol
,
321 .snapshot
= print_snapshot
,
322 .mkfile
= print_mkfile
,
323 .mkdir
= print_mkdir
,
324 .mknod
= print_mknod
,
325 .mkfifo
= print_mkfifo
,
326 .mksock
= print_mksock
,
327 .symlink
= print_symlink
,
328 .rename
= print_rename
,
330 .unlink
= print_unlink
,
331 .rmdir
= print_rmdir
,
332 .write
= print_write
,
333 .clone
= print_clone
,
334 .set_xattr
= print_set_xattr
,
335 .remove_xattr
= print_remove_xattr
,
336 .truncate
= print_truncate
,
337 .chmod
= print_chmod
,
338 .chown
= print_chown
,
339 .utimes
= print_utimes
,
340 .update_extent
= print_update_extent