Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 : : * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 : : * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 : : * Copyright (c) 1996-2001 Wichert Akkerman <wichert@cistron.nl>
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : * 3. The name of the author may not be used to endorse or promote products
17 : : * derived from this software without specific prior written permission.
18 : : *
19 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #include "defs.h"
32 : : #include <linux/ioctl.h>
33 : : #include "xlat/ioctl_dirs.h"
34 : :
35 : : #ifdef HAVE_LINUX_INPUT_H
36 : : # include <linux/input.h>
37 : : #endif
38 : :
39 : : #include "xlat/evdev_abs.h"
40 : : #include "xlat/evdev_ev.h"
41 : :
42 : : static int
43 : 42657 : compare(const void *a, const void *b)
44 : : {
45 : 42657 : const unsigned int code1 = (const uintptr_t) a;
46 : 42657 : const unsigned int code2 = ((struct_ioctlent *) b)->code;
47 [ + + ][ + + ]: 42657 : return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0;
48 : : }
49 : :
50 : : static const struct_ioctlent *
51 : 4025 : ioctl_lookup(const unsigned int code)
52 : : {
53 : : struct_ioctlent *iop;
54 : :
55 : 4025 : iop = bsearch((const void *) (const uintptr_t) code, ioctlent,
56 : : nioctlents, sizeof(ioctlent[0]), compare);
57 [ + + ]: 4050 : while (iop > ioctlent) {
58 : 3655 : iop--;
59 [ + + ]: 3655 : if (iop->code != code) {
60 : 3630 : iop++;
61 : 3630 : break;
62 : : }
63 : : }
64 : 4025 : return iop;
65 : : }
66 : :
67 : : static const struct_ioctlent *
68 : 3706 : ioctl_next_match(const struct_ioctlent *iop)
69 : : {
70 : 3706 : const unsigned int code = iop->code;
71 : 3706 : iop++;
72 [ + - ][ + + ]: 3706 : if (iop < ioctlent + nioctlents && iop->code == code)
73 : 76 : return iop;
74 : 3630 : return NULL;
75 : : }
76 : :
77 : : static void
78 : 145 : ioctl_print_code(const unsigned int code)
79 : : {
80 : 145 : tprints("_IOC(");
81 : 145 : printflags(ioctl_dirs, _IOC_DIR(code), "_IOC_???");
82 : 145 : tprintf(", %#x, %#x, %#x)",
83 : 290 : _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code));
84 : 145 : }
85 : :
86 : : static int
87 : 485 : evdev_decode_number(const unsigned int code)
88 : : {
89 : 485 : const unsigned int nr = _IOC_NR(code);
90 : :
91 [ + + ]: 485 : if (_IOC_DIR(code) == _IOC_WRITE) {
92 [ + + ][ + - ]: 160 : if (nr >= 0xc0 && nr <= 0xc0 + 0x3f) {
93 : 10 : tprints("EVIOCSABS(");
94 : 10 : printxval(evdev_abs, nr - 0xc0, "ABS_???");
95 : 10 : tprints(")");
96 : 10 : return 1;
97 : : }
98 : : }
99 : :
100 [ + + ]: 475 : if (_IOC_DIR(code) != _IOC_READ)
101 : 170 : return 0;
102 : :
103 [ + + ][ + + ]: 305 : if (nr >= 0x20 && nr <= 0x20 + 0x1f) {
104 : 135 : tprints("EVIOCGBIT(");
105 : 135 : printxval(evdev_ev, nr - 0x20, "EV_???");
106 : 135 : tprintf(", %u)", _IOC_SIZE(code));
107 : 135 : return 1;
108 [ + + ][ + + ]: 170 : } else if (nr >= 0x40 && nr <= 0x40 + 0x3f) {
109 : 10 : tprints("EVIOCGABS(");
110 : 10 : printxval(evdev_abs, nr - 0x40, "ABS_???");
111 : 10 : tprints(")");
112 : 10 : return 1;
113 : : }
114 : :
115 [ + + + + : 160 : switch (_IOC_NR(nr)) {
+ + + + +
+ ]
116 : : case 0x06:
117 : 10 : tprintf("EVIOCGNAME(%u)", _IOC_SIZE(code));
118 : 10 : return 1;
119 : : case 0x07:
120 : 10 : tprintf("EVIOCGPHYS(%u)", _IOC_SIZE(code));
121 : 10 : return 1;
122 : : case 0x08:
123 : 10 : tprintf("EVIOCGUNIQ(%u)", _IOC_SIZE(code));
124 : 10 : return 1;
125 : : case 0x09:
126 : 10 : tprintf("EVIOCGPROP(%u)", _IOC_SIZE(code));
127 : 10 : return 1;
128 : : case 0x0a:
129 : 10 : tprintf("EVIOCGMTSLOTS(%u)", _IOC_SIZE(code));
130 : 10 : return 1;
131 : : case 0x18:
132 : 10 : tprintf("EVIOCGKEY(%u)", _IOC_SIZE(code));
133 : 10 : return 1;
134 : : case 0x19:
135 : 10 : tprintf("EVIOCGLED(%u)", _IOC_SIZE(code));
136 : 10 : return 1;
137 : : case 0x1a:
138 : 10 : tprintf("EVIOCGSND(%u)", _IOC_SIZE(code));
139 : 10 : return 1;
140 : : case 0x1b:
141 : 10 : tprintf("EVIOCGSW(%u)", _IOC_SIZE(code));
142 : 10 : return 1;
143 : : default:
144 : 70 : return 0;
145 : : }
146 : : }
147 : :
148 : : static int
149 : 10 : hiddev_decode_number(const unsigned int code)
150 : : {
151 [ + - ]: 10 : if (_IOC_DIR(code) == _IOC_READ) {
152 [ - - - + : 10 : switch (_IOC_NR(code)) {
+ ]
153 : : case 0x04:
154 : 0 : tprintf("HIDIOCGRAWNAME(%u)", _IOC_SIZE(code));
155 : 0 : return 1;
156 : : case 0x05:
157 : 0 : tprintf("HIDIOCGRAWPHYS(%u)", _IOC_SIZE(code));
158 : 0 : return 1;
159 : : case 0x06:
160 : 0 : tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
161 : 0 : return 1;
162 : : case 0x12:
163 : 5 : tprintf("HIDIOCGPHYS(%u)", _IOC_SIZE(code));
164 : 5 : return 1;
165 : : default:
166 : 5 : return 0;
167 : : }
168 [ # # ]: 0 : } else if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) {
169 [ # # # ]: 0 : switch (_IOC_NR(code)) {
170 : : case 0x06:
171 : 0 : tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code));
172 : 0 : return 1;
173 : : case 0x07:
174 : 0 : tprintf("HIDIOCGFEATURE(%u)", _IOC_SIZE(code));
175 : 0 : return 1;
176 : : default:
177 : 0 : return 0;
178 : : }
179 : : }
180 : :
181 : 0 : return 0;
182 : : }
183 : :
184 : : static int
185 : 4025 : ioctl_decode_command_number(struct tcb *tcp)
186 : : {
187 : 4025 : const unsigned int code = tcp->u_arg[1];
188 : :
189 [ + + + - : 4025 : switch (_IOC_TYPE(code)) {
- - + ]
190 : : case 'E':
191 : 485 : return evdev_decode_number(code);
192 : : case 'H':
193 : 10 : return hiddev_decode_number(code);
194 : : case 'M':
195 [ + + ]: 195 : if (_IOC_DIR(code) == _IOC_WRITE) {
196 : 70 : tprintf("MIXER_WRITE(%u)", _IOC_NR(code));
197 : 70 : return 1;
198 [ + + ]: 125 : } else if (_IOC_DIR(code) == _IOC_READ) {
199 : 60 : tprintf("MIXER_READ(%u)", _IOC_NR(code));
200 : 60 : return 1;
201 : : }
202 : 65 : return 0;
203 : : case 'U':
204 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) {
205 : 0 : tprintf("UI_GET_SYSNAME(%u)", _IOC_SIZE(code));
206 : 0 : return 1;
207 : : }
208 : 0 : return 0;
209 : : case 'j':
210 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x13) {
211 : 0 : tprintf("JSIOCGNAME(%u)", _IOC_SIZE(code));
212 : 0 : return 1;
213 : : }
214 : 0 : return 0;
215 : : case 'k':
216 [ # # ][ # # ]: 0 : if (_IOC_DIR(code) == _IOC_WRITE && _IOC_NR(code) == 0) {
217 : 0 : tprintf("SPI_IOC_MESSAGE(%u)", _IOC_SIZE(code));
218 : 0 : return 1;
219 : : }
220 : 0 : return 0;
221 : : default:
222 : 3335 : return 0;
223 : : }
224 : : }
225 : :
226 : : static int
227 : 5935 : ioctl_decode(struct tcb *tcp)
228 : : {
229 : 5935 : const unsigned int code = tcp->u_arg[1];
230 : 5935 : const kernel_ulong_t arg = tcp->u_arg[2];
231 : :
232 [ + + + + : 5935 : switch (_IOC_TYPE(code)) {
- + - + +
+ - + - +
+ + + +
+ ]
233 : : #if defined(ALPHA) || defined(POWERPC)
234 : : case 'f': {
235 : : int ret = file_ioctl(tcp, code, arg);
236 : : if (ret != RVAL_DECODED)
237 : : return ret;
238 : : }
239 : : case 't':
240 : : case 'T':
241 : : return term_ioctl(tcp, code, arg);
242 : : #else /* !ALPHA */
243 : : case 'f':
244 : 10 : return file_ioctl(tcp, code, arg);
245 : : case 0x54:
246 : : #endif /* !ALPHA */
247 : 10 : return term_ioctl(tcp, code, arg);
248 : : case 0x89:
249 : 80 : return sock_ioctl(tcp, code, arg);
250 : : case 'p':
251 : 480 : return rtc_ioctl(tcp, code, arg);
252 : : case 0x03:
253 : 0 : return hdio_ioctl(tcp, code, arg);
254 : : case 0x12:
255 : 270 : return block_ioctl(tcp, code, arg);
256 : : case 'X':
257 : 0 : return fs_x_ioctl(tcp, code, arg);
258 : : case 0x22:
259 : 500 : return scsi_ioctl(tcp, code, arg);
260 : : case 'L':
261 : 405 : return loop_ioctl(tcp, code, arg);
262 : : case 'M':
263 : 235 : return mtd_ioctl(tcp, code, arg);
264 : : case 'o':
265 : : case 'O':
266 : 0 : return ubi_ioctl(tcp, code, arg);
267 : : case 'V':
268 : 520 : return v4l2_ioctl(tcp, code, arg);
269 : : case '=':
270 : 0 : return ptp_ioctl(tcp, code, arg);
271 : : #ifdef HAVE_LINUX_INPUT_H
272 : : case 'E':
273 : 790 : return evdev_ioctl(tcp, code, arg);
274 : : #endif
275 : : #ifdef HAVE_LINUX_USERFAULTFD_H
276 : : case 0xaa:
277 : 130 : return uffdio_ioctl(tcp, code, arg);
278 : : #endif
279 : : #ifdef HAVE_LINUX_BTRFS_H
280 : : case 0x94:
281 : 1540 : return btrfs_ioctl(tcp, code, arg);
282 : : #endif
283 : : #ifdef HAVE_LINUX_NSFS_H
284 : : case 0xb7:
285 : 55 : return nsfs_ioctl(tcp, code, arg);
286 : : #endif
287 : : #ifdef HAVE_LINUX_DM_IOCTL_H
288 : : case 0xfd:
289 : 860 : return dm_ioctl(tcp, code, arg);
290 : : #endif
291 : : default:
292 : 50 : break;
293 : : }
294 : 50 : return 0;
295 : : }
296 : :
297 : 5935 : SYS_FUNC(ioctl)
298 : : {
299 : : const struct_ioctlent *iop;
300 : : int ret;
301 : :
302 [ + + ]: 5935 : if (entering(tcp)) {
303 : 4025 : printfd(tcp, tcp->u_arg[0]);
304 : 4025 : tprints(", ");
305 : 4025 : ret = ioctl_decode_command_number(tcp);
306 [ + - ]: 4025 : if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) {
307 : 4025 : iop = ioctl_lookup(tcp->u_arg[1]);
308 [ + + ]: 4025 : if (iop) {
309 [ + + ]: 3630 : if (ret)
310 : 130 : tprints(" or ");
311 : 3630 : tprints(iop->symbol);
312 [ + + ]: 3706 : while ((iop = ioctl_next_match(iop)))
313 : 76 : tprintf(" or %s", iop->symbol);
314 [ + + ]: 395 : } else if (!ret) {
315 : 145 : ioctl_print_code(tcp->u_arg[1]);
316 : : }
317 : : }
318 : 4025 : ret = ioctl_decode(tcp);
319 : : } else {
320 : 1910 : ret = ioctl_decode(tcp) | RVAL_DECODED;
321 : : }
322 : :
323 [ + + ]: 5935 : if (ret & RVAL_DECODED) {
324 : 4025 : ret &= ~RVAL_DECODED;
325 [ + + ]: 4025 : if (ret)
326 : 3820 : --ret;
327 : : else
328 : 205 : tprintf(", %#" PRI_klx, tcp->u_arg[2]);
329 : 4025 : ret |= RVAL_DECODED;
330 : : } else {
331 [ + + ]: 1910 : if (ret)
332 : 565 : --ret;
333 : : }
334 : :
335 : 5935 : return ret;
336 : : }
|