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 ale aligned to 32 chars */
123 /* Operation specified ones */
130 /* For subvolume/snapshot operation only */
131 #define PRINT_DUMP_SUBVOL(user, path, title, fmt, ...) \
132 __print_dump(1, user, path, title, fmt, ##__VA_ARGS__)
134 /* For other operations */
135 #define PRINT_DUMP(user, path, title, fmt, ...) \
136 __print_dump(0, user, path, title, fmt, ##__VA_ARGS__)
138 static int print_subvol(const char *path
, const u8
*uuid
, u64 ctransid
,
141 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
143 uuid_unparse(uuid
, uuid_str
);
145 return PRINT_DUMP_SUBVOL(user
, path
, "subvol", "uuid=%s transid=%llu",
149 static int print_snapshot(const char *path
, const u8
*uuid
, u64 ctransid
,
150 const u8
*parent_uuid
, u64 parent_ctransid
,
153 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
154 char parent_uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
157 uuid_unparse(uuid
, uuid_str
);
158 uuid_unparse(parent_uuid
, parent_uuid_str
);
160 ret
= PRINT_DUMP_SUBVOL(user
, path
, "snapshot",
161 "uuid=%s transid=%llu parent_uuid=%s parent_transid=%llu",
162 uuid_str
, ctransid
, parent_uuid_str
,
167 static int print_mkfile(const char *path
, void *user
)
169 return PRINT_DUMP(user
, path
, "mkfile", NULL
);
172 static int print_mkdir(const char *path
, void *user
)
174 return PRINT_DUMP(user
, path
, "mkdir", NULL
);
177 static int print_mknod(const char *path
, u64 mode
, u64 dev
, void *user
)
179 return PRINT_DUMP(user
, path
, "mknod", "mode=%llo dev=0x%llx", mode
,
183 static int print_mkfifo(const char *path
, void *user
)
185 return PRINT_DUMP(user
, path
, "mkfifo", NULL
);
188 static int print_mksock(const char *path
, void *user
)
190 return PRINT_DUMP(user
, path
, "mksock", NULL
);
193 static int print_symlink(const char *path
, const char *lnk
, void *user
)
195 return PRINT_DUMP(user
, path
, "symlink", "dest=%s", lnk
);
198 static int print_rename(const char *from
, const char *to
, void *user
)
200 struct btrfs_dump_send_args
*r
= user
;
201 char full_to
[PATH_MAX
];
204 PATH_CAT_OR_RET("rename", full_to
, r
->full_subvol_path
, to
, ret
);
205 return PRINT_DUMP(user
, from
, "rename", "dest=%s", full_to
);
208 static int print_link(const char *path
, const char *lnk
, void *user
)
210 return PRINT_DUMP(user
, path
, "link", "dest=%s", lnk
);
213 static int print_unlink(const char *path
, void *user
)
215 return PRINT_DUMP(user
, path
, "unlink", NULL
);
218 static int print_rmdir(const char *path
, void *user
)
220 return PRINT_DUMP(user
, path
, "rmdir", NULL
);
223 static int print_write(const char *path
, const void *data
, u64 offset
,
226 return PRINT_DUMP(user
, path
, "write", "offset=%llu len=%llu",
230 static int print_clone(const char *path
, u64 offset
, u64 len
,
231 const u8
*clone_uuid
, u64 clone_ctransid
,
232 const char *clone_path
, u64 clone_offset
,
235 struct btrfs_dump_send_args
*r
= user
;
236 char full_path
[PATH_MAX
];
239 PATH_CAT_OR_RET("clone", full_path
, r
->full_subvol_path
, clone_path
,
241 return PRINT_DUMP(user
, path
, "clone",
242 "offset=%llu len=%llu from=%s clone_offset=%llu",
243 offset
, len
, full_path
, clone_offset
);
246 static int print_set_xattr(const char *path
, const char *name
,
247 const void *data
, int len
, void *user
)
249 return PRINT_DUMP(user
, path
, "set_xattr", "name=%s data=%.*s len=%d",
250 name
, len
, (char *)data
, len
);
253 static int print_remove_xattr(const char *path
, const char *name
, void *user
)
256 return PRINT_DUMP(user
, path
, "remove_xattr", "name=%s", name
);
259 static int print_truncate(const char *path
, u64 size
, void *user
)
261 return PRINT_DUMP(user
, path
, "truncate", "size=%llu", size
);
264 static int print_chmod(const char *path
, u64 mode
, void *user
)
266 return PRINT_DUMP(user
, path
, "chmod", "mode=%llo", mode
);
269 static int print_chown(const char *path
, u64 uid
, u64 gid
, void *user
)
271 return PRINT_DUMP(user
, path
, "chown", "gid=%llu uid=%llu", gid
, uid
);
274 static int sprintf_timespec(struct timespec
*ts
, char *dest
, int max_size
)
279 if (!localtime_r(&ts
->tv_sec
, &tm
)) {
280 error("failed to convert time %lld.%.9ld to local time",
281 (long long)ts
->tv_sec
, ts
->tv_nsec
);
284 ret
= strftime(dest
, max_size
, "%FT%T%z", &tm
);
287 "time %lld.%ld is too long to convert into readable string",
288 (long long)ts
->tv_sec
, ts
->tv_nsec
);
294 #define TIME_STRING_MAX 64
295 static int print_utimes(const char *path
, struct timespec
*at
,
296 struct timespec
*mt
, struct timespec
*ct
,
299 char at_str
[TIME_STRING_MAX
];
300 char mt_str
[TIME_STRING_MAX
];
301 char ct_str
[TIME_STRING_MAX
];
303 if (sprintf_timespec(at
, at_str
, TIME_STRING_MAX
- 1) < 0 ||
304 sprintf_timespec(mt
, mt_str
, TIME_STRING_MAX
- 1) < 0 ||
305 sprintf_timespec(ct
, ct_str
, TIME_STRING_MAX
- 1) < 0)
307 return PRINT_DUMP(user
, path
, "utimes", "atime=%s mtime=%s ctime=%s",
308 at_str
, mt_str
, ct_str
);
311 static int print_update_extent(const char *path
, u64 offset
, u64 len
,
314 return PRINT_DUMP(user
, path
, "update_extent", "offset=%llu len=%llu",
318 struct btrfs_send_ops btrfs_print_send_ops
= {
319 .subvol
= print_subvol
,
320 .snapshot
= print_snapshot
,
321 .mkfile
= print_mkfile
,
322 .mkdir
= print_mkdir
,
323 .mknod
= print_mknod
,
324 .mkfifo
= print_mkfifo
,
325 .mksock
= print_mksock
,
326 .symlink
= print_symlink
,
327 .rename
= print_rename
,
329 .unlink
= print_unlink
,
330 .rmdir
= print_rmdir
,
331 .write
= print_write
,
332 .clone
= print_clone
,
333 .set_xattr
= print_set_xattr
,
334 .remove_xattr
= print_remove_xattr
,
335 .truncate
= print_truncate
,
336 .chmod
= print_chmod
,
337 .chown
= print_chown
,
338 .utimes
= print_utimes
,
339 .update_extent
= print_update_extent