1 /* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com> 5 * Copyright (c) 1996-2001 Wichert Akkerman <wichert (at) 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 compare(const void *a, const void *b) 44 { 45 const unsigned int code1 = (const uintptr_t) a; 46 const unsigned int code2 = ((struct_ioctlent *) b)->code; 47 return (code1 > code2) ? 1 : (code1 < code2) ? -1 : 0; 48 } 49 50 static const struct_ioctlent * 51 ioctl_lookup(const unsigned int code) 52 { 53 struct_ioctlent *iop; 54 55 iop = bsearch((const void *) (const uintptr_t) code, ioctlent, 56 nioctlents, sizeof(ioctlent[0]), compare); 57 while (iop > ioctlent) { 58 iop--; 59 if (iop->code != code) { 60 iop++; 61 break; 62 } 63 } 64 return iop; 65 } 66 67 static const struct_ioctlent * 68 ioctl_next_match(const struct_ioctlent *iop) 69 { 70 const unsigned int code = iop->code; 71 iop++; 72 if (iop < ioctlent + nioctlents && iop->code == code) 73 return iop; 74 return NULL; 75 } 76 77 static void 78 ioctl_print_code(const unsigned int code) 79 { 80 tprints("_IOC("); 81 printflags(ioctl_dirs, _IOC_DIR(code), "_IOC_???"); 82 tprintf(", %#x, %#x, %#x)", 83 _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code)); 84 } 85 86 static int 87 evdev_decode_number(const unsigned int code) 88 { 89 const unsigned int nr = _IOC_NR(code); 90 91 if (_IOC_DIR(code) == _IOC_WRITE) { 92 if (nr >= 0xc0 && nr <= 0xc0 + 0x3f) { 93 tprints("EVIOCSABS("); 94 printxval(evdev_abs, nr - 0xc0, "ABS_???"); 95 tprints(")"); 96 return 1; 97 } 98 } 99 100 if (_IOC_DIR(code) != _IOC_READ) 101 return 0; 102 103 if (nr >= 0x20 && nr <= 0x20 + 0x1f) { 104 tprints("EVIOCGBIT("); 105 printxval(evdev_ev, nr - 0x20, "EV_???"); 106 tprintf(", %u)", _IOC_SIZE(code)); 107 return 1; 108 } else if (nr >= 0x40 && nr <= 0x40 + 0x3f) { 109 tprints("EVIOCGABS("); 110 printxval(evdev_abs, nr - 0x40, "ABS_???"); 111 tprints(")"); 112 return 1; 113 } 114 115 switch (_IOC_NR(nr)) { 116 case 0x06: 117 tprintf("EVIOCGNAME(%u)", _IOC_SIZE(code)); 118 return 1; 119 case 0x07: 120 tprintf("EVIOCGPHYS(%u)", _IOC_SIZE(code)); 121 return 1; 122 case 0x08: 123 tprintf("EVIOCGUNIQ(%u)", _IOC_SIZE(code)); 124 return 1; 125 case 0x09: 126 tprintf("EVIOCGPROP(%u)", _IOC_SIZE(code)); 127 return 1; 128 case 0x0a: 129 tprintf("EVIOCGMTSLOTS(%u)", _IOC_SIZE(code)); 130 return 1; 131 case 0x18: 132 tprintf("EVIOCGKEY(%u)", _IOC_SIZE(code)); 133 return 1; 134 case 0x19: 135 tprintf("EVIOCGLED(%u)", _IOC_SIZE(code)); 136 return 1; 137 case 0x1a: 138 tprintf("EVIOCGSND(%u)", _IOC_SIZE(code)); 139 return 1; 140 case 0x1b: 141 tprintf("EVIOCGSW(%u)", _IOC_SIZE(code)); 142 return 1; 143 default: 144 return 0; 145 } 146 } 147 148 static int 149 hiddev_decode_number(const unsigned int code) 150 { 151 if (_IOC_DIR(code) == _IOC_READ) { 152 switch (_IOC_NR(code)) { 153 case 0x04: 154 tprintf("HIDIOCGRAWNAME(%u)", _IOC_SIZE(code)); 155 return 1; 156 case 0x05: 157 tprintf("HIDIOCGRAWPHYS(%u)", _IOC_SIZE(code)); 158 return 1; 159 case 0x06: 160 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code)); 161 return 1; 162 case 0x12: 163 tprintf("HIDIOCGPHYS(%u)", _IOC_SIZE(code)); 164 return 1; 165 default: 166 return 0; 167 } 168 } else if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) { 169 switch (_IOC_NR(code)) { 170 case 0x06: 171 tprintf("HIDIOCSFEATURE(%u)", _IOC_SIZE(code)); 172 return 1; 173 case 0x07: 174 tprintf("HIDIOCGFEATURE(%u)", _IOC_SIZE(code)); 175 return 1; 176 default: 177 return 0; 178 } 179 } 180 181 return 0; 182 } 183 184 static int 185 ioctl_decode_command_number(struct tcb *tcp) 186 { 187 const unsigned int code = tcp->u_arg[1]; 188 189 switch (_IOC_TYPE(code)) { 190 case 'E': 191 return evdev_decode_number(code); 192 case 'H': 193 return hiddev_decode_number(code); 194 case 'M': 195 if (_IOC_DIR(code) == _IOC_WRITE) { 196 tprintf("MIXER_WRITE(%u)", _IOC_NR(code)); 197 return 1; 198 } else if (_IOC_DIR(code) == _IOC_READ) { 199 tprintf("MIXER_READ(%u)", _IOC_NR(code)); 200 return 1; 201 } 202 return 0; 203 case 'U': 204 if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) { 205 tprintf("UI_GET_SYSNAME(%u)", _IOC_SIZE(code)); 206 return 1; 207 } 208 return 0; 209 case 'j': 210 if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x13) { 211 tprintf("JSIOCGNAME(%u)", _IOC_SIZE(code)); 212 return 1; 213 } 214 return 0; 215 case 'k': 216 if (_IOC_DIR(code) == _IOC_WRITE && _IOC_NR(code) == 0) { 217 tprintf("SPI_IOC_MESSAGE(%u)", _IOC_SIZE(code)); 218 return 1; 219 } 220 return 0; 221 default: 222 return 0; 223 } 224 } 225 226 static int 227 ioctl_decode(struct tcb *tcp) 228 { 229 const unsigned int code = tcp->u_arg[1]; 230 const kernel_ulong_t arg = tcp->u_arg[2]; 231 232 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 return file_ioctl(tcp, code, arg); 245 case 0x54: 246 #endif /* !ALPHA */ 247 return term_ioctl(tcp, code, arg); 248 case 0x89: 249 return sock_ioctl(tcp, code, arg); 250 case 'p': 251 return rtc_ioctl(tcp, code, arg); 252 case 0x03: 253 return hdio_ioctl(tcp, code, arg); 254 case 0x12: 255 return block_ioctl(tcp, code, arg); 256 case 'X': 257 return fs_x_ioctl(tcp, code, arg); 258 case 0x22: 259 return scsi_ioctl(tcp, code, arg); 260 case 'L': 261 return loop_ioctl(tcp, code, arg); 262 case 'M': 263 return mtd_ioctl(tcp, code, arg); 264 case 'o': 265 case 'O': 266 return ubi_ioctl(tcp, code, arg); 267 case 'V': 268 return v4l2_ioctl(tcp, code, arg); 269 case '=': 270 return ptp_ioctl(tcp, code, arg); 271 #ifdef HAVE_LINUX_INPUT_H 272 case 'E': 273 return evdev_ioctl(tcp, code, arg); 274 #endif 275 #ifdef HAVE_LINUX_USERFAULTFD_H 276 case 0xaa: 277 return uffdio_ioctl(tcp, code, arg); 278 #endif 279 #ifdef HAVE_LINUX_BTRFS_H 280 case 0x94: 281 return btrfs_ioctl(tcp, code, arg); 282 #endif 283 #ifdef HAVE_LINUX_DM_IOCTL_H 284 case 0xfd: 285 return dm_ioctl(tcp, code, arg); 286 #endif 287 default: 288 break; 289 } 290 return 0; 291 } 292 293 SYS_FUNC(ioctl) 294 { 295 const struct_ioctlent *iop; 296 int ret; 297 298 if (entering(tcp)) { 299 printfd(tcp, tcp->u_arg[0]); 300 tprints(", "); 301 ret = ioctl_decode_command_number(tcp); 302 if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) { 303 iop = ioctl_lookup(tcp->u_arg[1]); 304 if (iop) { 305 if (ret) 306 tprints(" or "); 307 tprints(iop->symbol); 308 while ((iop = ioctl_next_match(iop))) 309 tprintf(" or %s", iop->symbol); 310 } else if (!ret) { 311 ioctl_print_code(tcp->u_arg[1]); 312 } 313 } 314 ret = ioctl_decode(tcp); 315 } else { 316 ret = ioctl_decode(tcp) | RVAL_DECODED; 317 } 318 319 if (ret & RVAL_DECODED) { 320 ret &= ~RVAL_DECODED; 321 if (ret) 322 --ret; 323 else 324 tprintf(", %#" PRI_klx, tcp->u_arg[2]); 325 ret |= RVAL_DECODED; 326 } else { 327 if (ret) 328 --ret; 329 } 330 331 return ret; 332 } 333