summaryrefslogtreecommitdiff
path: root/src/fs_0x94_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs_0x94_ioctl.c')
-rw-r--r--src/fs_0x94_ioctl.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/fs_0x94_ioctl.c b/src/fs_0x94_ioctl.c
new file mode 100644
index 000000000..e980d1761
--- /dev/null
+++ b/src/fs_0x94_ioctl.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com>
+ * Copyright (c) 2016-2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+#include "types/fs_0x94.h"
+#define XLAT_MACROS_ONLY
+# include "xlat/fs_0x94_ioctl_cmds.h"
+#undef XLAT_MACROS_ONLY
+
+static void
+decode_file_clone_range(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ struct_file_clone_range range;
+
+ tprints(", ");
+ if (!umove_or_printaddr(tcp, arg, &range)) {
+ tprint_struct_begin();
+ PRINT_FIELD_FD(range, src_fd, tcp);
+ tprint_struct_next();
+ PRINT_FIELD_U(range, src_offset);
+ tprint_struct_next();
+ PRINT_FIELD_U(range, src_length);
+ tprint_struct_next();
+ PRINT_FIELD_U(range, dest_offset);
+ tprint_struct_end();
+ }
+}
+
+static bool
+print_file_dedupe_range_info(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ const struct_file_dedupe_range_info *info = elem_buf;
+ unsigned int *count = data;
+
+ if (count) {
+ if (*count == 0) {
+ tprint_more_data_follows();
+ return false;
+ }
+ --*count;
+ }
+
+ if (entering(tcp)) {
+ tprint_struct_begin();
+ PRINT_FIELD_FD(*info, dest_fd, tcp);
+ tprint_struct_next();
+ PRINT_FIELD_U(*info, dest_offset);
+ } else {
+ tprint_struct_begin();
+ PRINT_FIELD_U(*info, bytes_deduped);
+ tprint_struct_next();
+ PRINT_FIELD_D(*info, status);
+ }
+ tprint_struct_end();
+
+ return true;
+}
+
+static int
+decode_file_dedupe_range(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ struct_file_dedupe_range range;
+ struct_file_dedupe_range_info info;
+ unsigned int *limit = NULL;
+ unsigned int count = 2;
+ bool rc;
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ return RVAL_IOCTL_DECODED;
+ else
+ tprint_value_changed();
+
+ if (umove_or_printaddr(tcp, arg, &range))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+
+ if (entering(tcp)) {
+ PRINT_FIELD_U(range, src_offset);
+ tprint_struct_next();
+ PRINT_FIELD_U(range, src_length);
+ tprint_struct_next();
+ PRINT_FIELD_U(range, dest_count);
+ tprints(", ");
+ }
+
+ tprints_field_name("info");
+
+ /* Limit how many elements we print in abbrev mode. */
+ if (abbrev(tcp) && range.dest_count > count)
+ limit = &count;
+
+ rc = print_array(tcp, arg + offsetof(typeof(range), info),
+ range.dest_count, &info, sizeof(info),
+ tfetch_mem,
+ print_file_dedupe_range_info, limit);
+
+ tprint_struct_end();
+
+ if (!rc || exiting(tcp))
+ return RVAL_IOCTL_DECODED;
+
+ return 0;
+}
+
+static void
+decode_fslabel(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ fs_0x94_label_t label;
+
+ tprints(", ");
+ if (!umove_or_printaddr(tcp, arg, &label))
+ print_quoted_cstring(label, sizeof(label));
+}
+
+int
+fs_0x94_ioctl(struct tcb *const tcp, const unsigned int code,
+ const kernel_ulong_t arg)
+{
+ switch (code) {
+ case FICLONE: /* W */
+ tprintf(", %d", (int) arg);
+ break;
+
+ case FICLONERANGE: /* W */
+ decode_file_clone_range(tcp, arg);
+ break;
+
+ case FIDEDUPERANGE: /* WR */
+ return decode_file_dedupe_range(tcp, arg);
+
+ case FS_IOC_GETFSLABEL: /* R */
+ if (entering(tcp))
+ return 0;
+ ATTRIBUTE_FALLTHROUGH;
+
+ case FS_IOC_SETFSLABEL: /* W */
+ decode_fslabel(tcp, arg);
+ break;
+
+ default:
+#ifdef HAVE_LINUX_BTRFS_H
+ return btrfs_ioctl(tcp, code, arg);
+#else
+ return RVAL_DECODED;
+#endif
+ };
+
+ return RVAL_IOCTL_DECODED;
+}