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 #include <linux/fiemap.h>
12 #include "xlat/fiemap_flags.h"
13 #include "xlat/fiemap_extent_flags.h"
14 #include "xlat/fs_ioc_flags.h"
15
16 static bool
17 print_fiemap_extent(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
18 {
19 const struct fiemap_extent *fe = elem_buf;
20
21 tprint_struct_begin();
22 PRINT_FIELD_U(*fe, fe_logical);
23 tprint_struct_next();
24 PRINT_FIELD_U(*fe, fe_physical);
25 tprint_struct_next();
26 PRINT_FIELD_U(*fe, fe_length);
27 tprint_struct_next();
28 PRINT_FIELD_FLAGS(*fe, fe_flags, fiemap_extent_flags,
29 "FIEMAP_EXTENT_???");
30 tprint_struct_end();
31
32 return true;
33 }
34
35 static int
36 decode_fiemap(struct tcb *const tcp, const kernel_ulong_t arg)
37 {
38 struct fiemap args;
39
40 if (entering(tcp))
41 tprint_arg_next();
42 else if (syserror(tcp))
43 return RVAL_IOCTL_DECODED;
44 else
45 tprint_value_changed();
46
47 if (umove_or_printaddr(tcp, arg, &args))
48 return RVAL_IOCTL_DECODED;
49
50 if (entering(tcp)) {
51 tprint_struct_begin();
52 PRINT_FIELD_U(args, fm_start);
53 tprint_struct_next();
54 PRINT_FIELD_U(args, fm_length);
55 tprint_struct_next();
56 PRINT_FIELD_FLAGS(args, fm_flags, fiemap_flags,
57 "FIEMAP_FLAG_???");
58 tprint_struct_next();
59 PRINT_FIELD_U(args, fm_extent_count);
60 tprint_struct_end();
61 return 0;
62 }
63
64 tprint_struct_begin();
65 PRINT_FIELD_FLAGS(args, fm_flags, fiemap_flags, "FIEMAP_FLAG_???");
66 tprint_struct_next();
67 PRINT_FIELD_U(args, fm_mapped_extents);
68 if (abbrev(tcp)) {
69 tprint_struct_next();
70 tprint_more_data_follows();
71 } else {
72 struct fiemap_extent fe;
73 tprint_struct_next();
74 tprints_field_name("fm_extents");
75 print_array(tcp, arg + offsetof(typeof(args), fm_extents),
76 args.fm_mapped_extents, &fe, sizeof(fe),
77 tfetch_mem, print_fiemap_extent, 0);
78 }
79 tprint_struct_end();
80
81 return RVAL_IOCTL_DECODED;
82 }
83
84 static void
85 decode_fs_ioc_flags(struct tcb *const tcp, const kernel_ulong_t arg)
86 {
87 unsigned int flags;
88
89 if (!umove_or_printaddr(tcp, arg, &flags)) {
90 tprint_indirect_begin();
91 printflags(fs_ioc_flags, flags, "FS_???_FL");
92 tprint_indirect_end();
93 }
94 }
95
96 int
97 fs_f_ioctl(struct tcb *const tcp, const unsigned int code,
98 const kernel_ulong_t arg)
99 {
100 switch (code) {
101 case FS_IOC_FIEMAP:
102 return decode_fiemap(tcp, arg);
103
104 case FS_IOC_GETFLAGS:
105 #if SIZEOF_LONG > 4
106 case FS_IOC32_GETFLAGS:
107 #endif
108 if (entering(tcp))
109 return 0;
110 ATTRIBUTE_FALLTHROUGH;
111
112 case FS_IOC_SETFLAGS:
113 #if SIZEOF_LONG > 4
114 case FS_IOC32_SETFLAGS:
115 #endif
116 tprint_arg_next();
117 decode_fs_ioc_flags(tcp, arg);
118 break;
119
120 default:
121 return RVAL_DECODED;
122 };
123
124 return RVAL_IOCTL_DECODED;
125 }