(root)/
strace-6.5/
src/
term.c
       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  }