1 /*
2 * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com>
3 * Copyright (c) 2016-2021 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #include "defs.h"
10 #include <linux/fs.h>
11
12 static void
13 decode_file_clone_range(struct tcb *const tcp, const kernel_ulong_t arg)
14 {
15 struct file_clone_range range;
16
17 if (!umove_or_printaddr(tcp, arg, &range)) {
18 tprint_struct_begin();
19 PRINT_FIELD_FD(range, src_fd, tcp);
20 tprint_struct_next();
21 PRINT_FIELD_U(range, src_offset);
22 tprint_struct_next();
23 PRINT_FIELD_U(range, src_length);
24 tprint_struct_next();
25 PRINT_FIELD_U(range, dest_offset);
26 tprint_struct_end();
27 }
28 }
29
30 static bool
31 print_file_dedupe_range_info(struct tcb *tcp, void *elem_buf,
32 size_t elem_size, void *data)
33 {
34 const struct file_dedupe_range_info *info = elem_buf;
35 unsigned int *count = data;
36
37 if (count) {
38 if (*count == 0) {
39 tprint_more_data_follows();
40 return false;
41 }
42 --*count;
43 }
44
45 if (entering(tcp)) {
46 tprint_struct_begin();
47 PRINT_FIELD_FD(*info, dest_fd, tcp);
48 tprint_struct_next();
49 PRINT_FIELD_U(*info, dest_offset);
50 } else {
51 tprint_struct_begin();
52 PRINT_FIELD_U(*info, bytes_deduped);
53 tprint_struct_next();
54 PRINT_FIELD_D(*info, status);
55 }
56 tprint_struct_end();
57
58 return true;
59 }
60
61 static int
62 decode_file_dedupe_range(struct tcb *const tcp, const kernel_ulong_t arg)
63 {
64 struct file_dedupe_range range;
65 struct file_dedupe_range_info info;
66 unsigned int *limit = NULL;
67 unsigned int count = 2;
68 bool rc;
69
70 if (entering(tcp))
71 tprint_arg_next();
72 else if (syserror(tcp))
73 return RVAL_IOCTL_DECODED;
74 else
75 tprint_value_changed();
76
77 if (umove_or_printaddr(tcp, arg, &range))
78 return RVAL_IOCTL_DECODED;
79
80 tprint_struct_begin();
81
82 if (entering(tcp)) {
83 PRINT_FIELD_U(range, src_offset);
84 tprint_struct_next();
85 PRINT_FIELD_U(range, src_length);
86 tprint_struct_next();
87 PRINT_FIELD_U(range, dest_count);
88 tprint_struct_next();
89 }
90
91 tprints_field_name("info");
92
93 /* Limit how many elements we print in abbrev mode. */
94 if (abbrev(tcp) && range.dest_count > count)
95 limit = &count;
96
97 rc = print_array(tcp, arg + offsetof(typeof(range), info),
98 range.dest_count, &info, sizeof(info),
99 tfetch_mem,
100 print_file_dedupe_range_info, limit);
101
102 tprint_struct_end();
103
104 if (!rc || exiting(tcp))
105 return RVAL_IOCTL_DECODED;
106
107 return 0;
108 }
109
110 static void
111 decode_fslabel(struct tcb *const tcp, const kernel_ulong_t arg)
112 {
113 char label[FSLABEL_MAX];
114
115 if (!umove_or_printaddr(tcp, arg, &label))
116 print_quoted_cstring(label, sizeof(label));
117 }
118
119 int
120 fs_0x94_ioctl(struct tcb *const tcp, const unsigned int code,
121 const kernel_ulong_t arg)
122 {
123 switch (code) {
124 case FICLONE: /* W */
125 tprint_arg_next();
126 PRINT_VAL_D((int) arg);
127 break;
128
129 case FICLONERANGE: /* W */
130 tprint_arg_next();
131 decode_file_clone_range(tcp, arg);
132 break;
133
134 case FIDEDUPERANGE: /* WR */
135 return decode_file_dedupe_range(tcp, arg);
136
137 case FS_IOC_GETFSLABEL: /* R */
138 if (entering(tcp))
139 return 0;
140 ATTRIBUTE_FALLTHROUGH;
141
142 case FS_IOC_SETFSLABEL: /* W */
143 tprint_arg_next();
144 decode_fslabel(tcp, arg);
145 break;
146
147 default:
148 return btrfs_ioctl(tcp, code, arg);
149 };
150
151 return RVAL_IOCTL_DECODED;
152 }