1 /*
2 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3 * Copyright (c) 1996-2022 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #include "defs.h"
10 /*
11 * The C library's definition of struct termios might differ from
12 * the kernel one, and we need to use the kernel layout.
13 */
14 #include <linux/termios.h>
15
16 #include "xlat/tcxonc_options.h"
17 #include "xlat/tcflsh_options.h"
18 #include "xlat/baud_options.h"
19 #include "xlat/modem_flags.h"
20
21 #include "xlat/term_cflags.h"
22 #include "xlat/term_cflags_csize.h"
23 #include "xlat/term_iflags.h"
24 #include "xlat/term_lflags.h"
25 #include "xlat/term_oflags.h"
26 #include "xlat/term_oflags_bsdly.h"
27 #include "xlat/term_oflags_crdly.h"
28 #include "xlat/term_oflags_ffdly.h"
29 #include "xlat/term_oflags_nldly.h"
30 #include "xlat/term_oflags_tabdly.h"
31 #include "xlat/term_oflags_vtdly.h"
32
33 #include "xlat/term_line_discs.h"
34
35 #include "xlat/termios_cc.h"
36
37 #ifdef _VMIN /* thanks, alpha and powerpc */
38 # include "xlat/termio_cc.h"
39 #else
40 # define termio_cc termios_cc
41 #endif
42
43 #include "xlat/term_cmds_overlapping.h"
44
45 static void
46 decode_oflag(uint64_t val)
47 {
48 static const struct {
49 const struct xlat *xl;
50 uint64_t mask;
51 const char *dfl;
52 } xlats[] = {
53 { term_oflags_nldly, NLDLY, "NL?" },
54 { term_oflags_crdly, CRDLY, "CR?" },
55 { term_oflags_tabdly, TABDLY, "TAB?" },
56 { term_oflags_bsdly, BSDLY, "BS?" },
57 { term_oflags_vtdly, VTDLY, "VT?" },
58 { term_oflags_ffdly, FFDLY, "FF?" },
59 };
60
61 tprint_flags_begin();
62 for (unsigned int i = 0; i < ARRAY_SIZE(xlats); i++) {
63 printxval64(xlats[i].xl, val & xlats[i].mask, xlats[i].dfl);
64 tprint_flags_or();
65
66 val &= ~xlats[i].mask;
67 }
68
69 printflags64_in(term_oflags, val, NULL);
70 tprint_flags_end();
71 }
72
73 static void
74 decode_cflag(uint64_t val)
75 {
76 tprint_flags_begin();
77 printxval64(baud_options, val & CBAUD, "B???");
78 tprint_flags_or();
79
80 if (val & CIBAUD) {
81 tprint_shift_begin();
82 printxval64(baud_options, (val & CIBAUD) >> IBSHIFT, "B???");
83 tprint_shift();
84 print_xlat(IBSHIFT);
85 tprint_shift_end();
86 tprint_flags_or();
87 }
88
89 printxval64(term_cflags_csize, val & CSIZE, "CS?");
90 tprint_flags_or();
91
92 val &= ~(CBAUD | CIBAUD | CSIZE);
93 printflags64_in(term_cflags, val, NULL);
94 tprint_flags_end();
95 }
96
97 static void
98 decode_flags(uint64_t iflag, uint64_t oflag, uint64_t cflag, uint64_t lflag)
99 {
100 tprints_field_name("c_iflag");
101 printflags64(term_iflags, iflag, NULL);
102
103 tprint_struct_next();
104 tprints_field_name("c_oflag");
105 decode_oflag(oflag);
106
107 tprint_struct_next();
108 tprints_field_name("c_cflag");
109 decode_cflag(cflag);
110
111 tprint_struct_next();
112 tprints_field_name("c_lflag");
113 printflags64(term_lflags, lflag, NULL);
114 }
115
116 static void
117 print_cc_char(bool *first, const unsigned char *data, const char *s,
118 unsigned int idx)
119 {
120 if (*first)
121 *first = false;
122 else
123 tprint_array_next();
124
125 tprint_array_index_begin();
126 if (s)
127 tprints_string(s);
128 else
129 PRINT_VAL_U(idx);
130 tprint_array_index_equal();
131
132 PRINT_VAL_X(data[idx]);
133 tprint_array_index_end();
134 }
135
136 static void
137 decode_term_cc(const struct xlat *xl, const unsigned char *data, unsigned size)
138 {
139 tprints_field_name("c_cc");
140 tprint_array_begin();
141 bool first = true;
142 for (unsigned int i = 0; i < size; i++)
143 print_cc_char(&first, data, xlookup(xl, i), i);
144 tprint_array_end();
145 }
146
147 #ifdef HAVE_STRUCT_TERMIOS2
148 static void
149 decode_termios2(struct tcb *const tcp, const kernel_ulong_t addr)
150 {
151 struct termios2 tios;
152 if (umove_or_printaddr(tcp, addr, &tios))
153 return;
154
155 tprint_struct_begin();
156 decode_flags(tios.c_iflag, tios.c_oflag, tios.c_cflag, tios.c_lflag);
157 tprint_struct_next();
158
159 if (abbrev(tcp)) {
160 tprint_more_data_follows();
161 } else {
162 PRINT_FIELD_XVAL(tios, c_line, term_line_discs, "N_???");
163
164 tprint_struct_next();
165 /* SPARC has two additional bytes in c_cc. */
166 decode_term_cc(termios_cc, tios.c_cc, sizeof(tios.c_cc));
167
168 tprint_struct_next();
169 PRINT_FIELD_U(tios, c_ispeed);
170
171 tprint_struct_next();
172 PRINT_FIELD_U(tios, c_ospeed);
173 }
174 tprint_struct_end();
175 }
176 #endif /* HAVE_STRUCT_TERMIOS2 */
177
178 static void
179 decode_termios(struct tcb *const tcp, const kernel_ulong_t addr)
180 {
181 struct termios tios;
182 if (umove_or_printaddr(tcp, addr, &tios))
183 return;
184
185 tprint_struct_begin();
186 decode_flags(tios.c_iflag, tios.c_oflag, tios.c_cflag, tios.c_lflag);
187 tprint_struct_next();
188
189 if (abbrev(tcp)) {
190 tprint_more_data_follows();
191 } else {
192 PRINT_FIELD_XVAL(tios, c_line, term_line_discs, "N_???");
193
194 tprint_struct_next();
195 /*
196 * Fun fact: MIPS has NCCS defined to 23, SPARC to 17 and
197 * everything else to 19.
198 */
199 decode_term_cc(termios_cc, tios.c_cc,
200 MIN(NCCS, sizeof(tios.c_cc)));
201
202 /*
203 * alpha and powerpc have those in struct termios instead of
204 * having a separate struct termios2.
205 */
206 #ifdef HAVE_STRUCT_TERMIOS_C_ISPEED
207 tprint_struct_next();
208 PRINT_FIELD_U(tios, c_ispeed);
209 #endif
210 #ifdef HAVE_STRUCT_TERMIOS_C_OSPEED
211 tprint_struct_next();
212 PRINT_FIELD_U(tios, c_ospeed);
213 #endif
214 }
215 tprint_struct_end();
216 }
217
218 static void
219 decode_termio(struct tcb *const tcp, const kernel_ulong_t addr)
220 {
221 struct termio tio;
222 if (umove_or_printaddr(tcp, addr, &tio))
223 return;
224
225 tprint_struct_begin();
226 decode_flags(tio.c_iflag, tio.c_oflag, tio.c_cflag, tio.c_lflag);
227 tprint_struct_next();
228
229 if (abbrev(tcp)) {
230 tprint_more_data_follows();
231 } else {
232 PRINT_FIELD_XVAL(tio, c_line, term_line_discs, "N_???");
233
234 tprint_struct_next();
235 decode_term_cc(termio_cc, tio.c_cc,
236 MIN(NCC, sizeof(tio.c_cc)));
237 }
238 tprint_struct_end();
239 }
240
241 static void
242 decode_winsize(struct tcb *const tcp, const kernel_ulong_t addr)
243 {
244 struct winsize ws;
245 if (umove_or_printaddr(tcp, addr, &ws))
246 return;
247
248 tprint_struct_begin();
249 PRINT_FIELD_U(ws, ws_row);
250
251 tprint_struct_next();
252 PRINT_FIELD_U(ws, ws_col);
253
254 tprint_struct_next();
255 PRINT_FIELD_U(ws, ws_xpixel);
256
257 tprint_struct_next();
258 PRINT_FIELD_U(ws, ws_ypixel);
259
260 tprint_struct_end();
261 }
262
263 #ifdef TIOCGSIZE
264 static void
265 decode_ttysize(struct tcb *const tcp, const kernel_ulong_t addr)
266 {
267 struct ttysize ts;
268 if (umove_or_printaddr(tcp, addr, &ts))
269 return;
270
271 tprint_struct_begin();
272 PRINT_FIELD_U(ts, ts_lines);
273 tprint_struct_next();
274 PRINT_FIELD_U(ts, ts_cols);
275 tprint_struct_end();
276 }
277 #endif
278
279 static void
280 decode_modem_flags(struct tcb *const tcp, const kernel_ulong_t addr)
281 {
282 unsigned int flags;
283 if (umove_or_printaddr(tcp, addr, &flags))
284 return;
285
286 tprint_indirect_begin();
287 printflags(modem_flags, flags, "TIOCM_???");
288 tprint_indirect_end();
289 }
290
291 int
292 term_ioctl(struct tcb *const tcp, const unsigned int code,
293 const kernel_ulong_t arg)
294 {
295 switch (code) {
296 #ifdef HAVE_STRUCT_TERMIOS2
297 /* struct termios2 */
298 # ifdef TCGETS2
299 case TCGETS2:
300 # endif
301 if (entering(tcp))
302 return 0;
303 ATTRIBUTE_FALLTHROUGH;
304 # ifdef TCSETS2
305 case TCSETS2:
306 # endif
307 # ifdef TCSETSW2
308 case TCSETSW2:
309 # endif
310 # ifdef TCSETSF2
311 case TCSETSF2:
312 # endif
313 tprint_arg_next();
314 decode_termios2(tcp, arg);
315 break;
316 #endif /* HAVE_STRUCT_TERMIOS2 */
317
318 /* struct termios */
319 case TCGETS:
320 case TIOCGLCKTRMIOS:
321 if (entering(tcp))
322 return 0;
323 ATTRIBUTE_FALLTHROUGH;
324 case TCSETS:
325 case TCSETSW:
326 case TCSETSF:
327 case TIOCSLCKTRMIOS:
328 tprint_arg_next();
329 decode_termios(tcp, arg);
330 break;
331
332 /* struct termio */
333 case TCGETA:
334 if (entering(tcp))
335 return 0;
336 ATTRIBUTE_FALLTHROUGH;
337 case TCSETA:
338 case TCSETAW:
339 case TCSETAF:
340 tprint_arg_next();
341 decode_termio(tcp, arg);
342 break;
343
344 /* struct winsize */
345 case TIOCGWINSZ:
346 if (entering(tcp))
347 return 0;
348 ATTRIBUTE_FALLTHROUGH;
349 case TIOCSWINSZ:
350 tprint_arg_next();
351 decode_winsize(tcp, arg);
352 break;
353
354 /* struct ttysize */
355 #ifdef TIOCGSIZE
356 case TIOCGSIZE:
357 if (entering(tcp))
358 return 0;
359 ATTRIBUTE_FALLTHROUGH;
360 case TIOCSSIZE:
361 tprint_arg_next();
362 decode_ttysize(tcp, arg);
363 break;
364 #endif
365
366 /* ioctls with a direct decodable arg */
367 case TCXONC:
368 tprint_arg_next();
369 printxval64(tcxonc_options, arg, "TC???");
370 break;
371 case TCFLSH:
372 tprint_arg_next();
373 printxval64(tcflsh_options, arg, "TC???");
374 break;
375 case TCSBRK:
376 case TCSBRKP:
377 case TIOCSCTTY:
378 tprint_arg_next();
379 PRINT_VAL_D((int) arg);
380 break;
381
382 /* ioctls with an indirect parameter displayed as modem flags */
383 case TIOCMGET:
384 if (entering(tcp))
385 return 0;
386 ATTRIBUTE_FALLTHROUGH;
387 case TIOCMBIS:
388 case TIOCMBIC:
389 case TIOCMSET:
390 tprint_arg_next();
391 decode_modem_flags(tcp, arg);
392 break;
393
394 /* ioctls with an indirect parameter displayed in decimal */
395 case TIOCGPGRP:
396 case TIOCGSID:
397 case TIOCGETD:
398 case TIOCGSOFTCAR:
399 case TIOCGPTN:
400 case FIONREAD:
401 case TIOCOUTQ:
402 #ifdef TIOCGEXCL
403 case TIOCGEXCL:
404 #endif
405 #ifdef TIOCGDEV
406 case TIOCGDEV:
407 #endif
408 if (entering(tcp))
409 return 0;
410 ATTRIBUTE_FALLTHROUGH;
411 case TIOCSPGRP:
412 case TIOCSETD:
413 case FIONBIO:
414 case FIOASYNC:
415 case TIOCPKT:
416 case TIOCSSOFTCAR:
417 case TIOCSPTLCK:
418 tprint_arg_next();
419 printnum_int(tcp, arg, "%d");
420 break;
421
422 /* ioctls with an indirect parameter displayed as a char */
423 case TIOCSTI:
424 tprint_arg_next();
425 printstrn(tcp, arg, 1);
426 break;
427
428 /* ioctls with no parameters */
429
430 case TIOCSBRK:
431 case TIOCCBRK:
432 case TIOCCONS:
433 case TIOCNOTTY:
434 case TIOCEXCL:
435 case TIOCNXCL:
436 case FIOCLEX:
437 case FIONCLEX:
438 #ifdef TIOCVHANGUP
439 case TIOCVHANGUP:
440 #endif
441 #ifdef TIOCSSERIAL
442 case TIOCSSERIAL:
443 #endif
444 break;
445
446 /* ioctls which are unknown */
447
448 default:
449 return RVAL_DECODED;
450 }
451
452 return RVAL_IOCTL_DECODED;
453 }
454
455 /*
456 * TTY and SND ioctl commands may clash, for example:
457 *
458 * 0x00005404
459 * { "SNDCTL_TMR_CONTINUE", 0x00005404 },
460 * { "TCSETSF", 0x00005404 },
461 * 0x00005403
462 * { "SNDCTL_TMR_STOP", 0x00005403 },
463 * { "TCSETSW", 0x00005403 },
464 * 0x00005402
465 * { "SNDCTL_TMR_START", 0x00005402 },
466 * { "TCSETS", 0x00005402 },
467 *
468 * This function tries to resolve the collision using the device information
469 * associated with the specified file descriptor.
470 */
471 int
472 term_ioctl_decode_command_number(struct tcb *tcp,
473 const struct finfo *finfo,
474 unsigned int code)
475 {
476 /*
477 * See Linux kernel Documentation/admin-guide/devices.txt
478 */
479 if (finfo
480 && finfo->type == FINFO_DEV_CHR
481 && ((3 <= finfo->dev.major && finfo->dev.major <= 5) ||
482 (136 <= finfo->dev.major && finfo->dev.major <= 143))) {
483 const char *str = xlookup(term_cmds_overlapping, code);
484 if (str) {
485 tprints_string(str);
486 return IOCTL_NUMBER_STOP_LOOKUP;
487 }
488 }
489 return 0;
490 }