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
);
117 /* Short paths ale aligned to 32 chars */
121 /* Operation specified ones */
128 /* For subvolume/snapshot operation only */
129 #define PRINT_DUMP_SUBVOL(user, path, title, fmt, ...) \
130 __print_dump(1, user, path, title, fmt, ##__VA_ARGS__)
132 /* For other operations */
133 #define PRINT_DUMP(user, path, title, fmt, ...) \
134 __print_dump(0, user, path, title, fmt, ##__VA_ARGS__)
136 static int print_subvol(const char *path
, const u8
*uuid
, u64 ctransid
,
139 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
141 uuid_unparse(uuid
, uuid_str
);
143 return PRINT_DUMP_SUBVOL(user
, path
, "subvol", "uuid=%s transid=%llu",
147 static int print_snapshot(const char *path
, const u8
*uuid
, u64 ctransid
,
148 const u8
*parent_uuid
, u64 parent_ctransid
,
151 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
152 char parent_uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
155 uuid_unparse(uuid
, uuid_str
);
156 uuid_unparse(parent_uuid
, parent_uuid_str
);
158 ret
= PRINT_DUMP_SUBVOL(user
, path
, "snapshot",
159 "uuid=%s transid=%llu parent_uuid=%s parent_transid=%llu",
160 uuid_str
, ctransid
, parent_uuid_str
,
165 static int print_mkfile(const char *path
, void *user
)
167 return PRINT_DUMP(user
, path
, "mkfile", NULL
);
170 static int print_mkdir(const char *path
, void *user
)
172 return PRINT_DUMP(user
, path
, "mkdir", NULL
);
175 static int print_mknod(const char *path
, u64 mode
, u64 dev
, void *user
)
177 return PRINT_DUMP(user
, path
, "mknod", "mode=%llo dev=0x%llx", mode
,
181 static int print_mkfifo(const char *path
, void *user
)
183 return PRINT_DUMP(user
, path
, "mkfifo", NULL
);
186 static int print_mksock(const char *path
, void *user
)
188 return PRINT_DUMP(user
, path
, "mksock", NULL
);
191 static int print_symlink(const char *path
, const char *lnk
, void *user
)
193 return PRINT_DUMP(user
, path
, "symlink", "dest=%s", lnk
);
196 static int print_rename(const char *from
, const char *to
, void *user
)
198 struct btrfs_dump_send_args
*r
= user
;
199 char full_to
[PATH_MAX
];
202 PATH_CAT_OR_RET("rename", full_to
, r
->full_subvol_path
, to
, ret
);
203 return PRINT_DUMP(user
, from
, "rename", "dest=%s", full_to
);
206 static int print_link(const char *path
, const char *lnk
, void *user
)
208 return PRINT_DUMP(user
, path
, "link", "dest=%s", lnk
);
211 static int print_unlink(const char *path
, void *user
)
213 return PRINT_DUMP(user
, path
, "unlink", NULL
);
216 static int print_rmdir(const char *path
, void *user
)
218 return PRINT_DUMP(user
, path
, "rmdir", NULL
);
221 static int print_write(const char *path
, const void *data
, u64 offset
,
224 return PRINT_DUMP(user
, path
, "write", "offset=%llu len=%llu",
228 static int print_clone(const char *path
, u64 offset
, u64 len
,
229 const u8
*clone_uuid
, u64 clone_ctransid
,
230 const char *clone_path
, u64 clone_offset
,
233 struct btrfs_dump_send_args
*r
= user
;
234 char full_path
[PATH_MAX
];
237 PATH_CAT_OR_RET("clone", full_path
, r
->full_subvol_path
, clone_path
,
239 return PRINT_DUMP(user
, path
, "clone",
240 "offset=%llu len=%llu from=%s clone_offset=%llu",
241 offset
, len
, full_path
, clone_offset
);
244 static int print_set_xattr(const char *path
, const char *name
,
245 const void *data
, int len
, void *user
)
247 return PRINT_DUMP(user
, path
, "set_xattr", "name=%s data=%.*s len=%d",
248 name
, len
, (char *)data
, len
);
251 static int print_remove_xattr(const char *path
, const char *name
, void *user
)
254 return PRINT_DUMP(user
, path
, "remove_xattr", "name=%s", name
);
257 static int print_truncate(const char *path
, u64 size
, void *user
)
259 return PRINT_DUMP(user
, path
, "truncate", "size=%llu", size
);
262 static int print_chmod(const char *path
, u64 mode
, void *user
)
264 return PRINT_DUMP(user
, path
, "chmod", "mode=%llo", mode
);
267 static int print_chown(const char *path
, u64 uid
, u64 gid
, void *user
)
269 return PRINT_DUMP(user
, path
, "chown", "gid=%llu uid=%llu", gid
, uid
);
272 static int sprintf_timespec(struct timespec
*ts
, char *dest
, int max_size
)
277 if (!localtime_r(&ts
->tv_sec
, &tm
)) {
278 error("failed to convert time %lld.%.9ld to local time",
279 (long long)ts
->tv_sec
, ts
->tv_nsec
);
282 ret
= strftime(dest
, max_size
, "%FT%T%z", &tm
);
285 "time %lld.%ld is too long to convert into readable string",
286 (long long)ts
->tv_sec
, ts
->tv_nsec
);
292 #define TIME_STRING_MAX 64
293 static int print_utimes(const char *path
, struct timespec
*at
,
294 struct timespec
*mt
, struct timespec
*ct
,
297 char at_str
[TIME_STRING_MAX
];
298 char mt_str
[TIME_STRING_MAX
];
299 char ct_str
[TIME_STRING_MAX
];
301 if (sprintf_timespec(at
, at_str
, TIME_STRING_MAX
- 1) < 0 ||
302 sprintf_timespec(mt
, mt_str
, TIME_STRING_MAX
- 1) < 0 ||
303 sprintf_timespec(ct
, ct_str
, TIME_STRING_MAX
- 1) < 0)
305 return PRINT_DUMP(user
, path
, "utimes", "atime=%s mtime=%s ctime=%s",
306 at_str
, mt_str
, ct_str
);
309 static int print_update_extent(const char *path
, u64 offset
, u64 len
,
312 return PRINT_DUMP(user
, path
, "update_extent", "offset=%llu len=%llu",
316 struct btrfs_send_ops btrfs_print_send_ops
= {
317 .subvol
= print_subvol
,
318 .snapshot
= print_snapshot
,
319 .mkfile
= print_mkfile
,
320 .mkdir
= print_mkdir
,
321 .mknod
= print_mknod
,
322 .mkfifo
= print_mkfifo
,
323 .mksock
= print_mksock
,
324 .symlink
= print_symlink
,
325 .rename
= print_rename
,
327 .unlink
= print_unlink
,
328 .rmdir
= print_rmdir
,
329 .write
= print_write
,
330 .clone
= print_clone
,
331 .set_xattr
= print_set_xattr
,
332 .remove_xattr
= print_remove_xattr
,
333 .truncate
= print_truncate
,
334 .chmod
= print_chmod
,
335 .chown
= print_chown
,
336 .utimes
= print_utimes
,
337 .update_extent
= print_update_extent