(root)/
strace-6.5/
tests-m32/
ioctl_termios.c
       1  /*
       2   * Check decoding of struct termio{,s,s2}-related commands of ioctl syscall.
       3   *
       4   * Copyright (c) 2018-2022 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include "scno.h"
      12  
      13  #include <errno.h>
      14  #include <stdbool.h>
      15  #include <stdint.h>
      16  #include <stdio.h>
      17  #include <string.h>
      18  #include <unistd.h>
      19  
      20  #include <linux/fcntl.h>
      21  #include <linux/ioctl.h>
      22  #include <linux/termios.h>
      23  #include <linux/tty.h>
      24  
      25  #include <sys/param.h>
      26  
      27  #include "xlat.h"
      28  #include "xlat/baud_options.h"
      29  #include "xlat/term_line_discs.h"
      30  
      31  #ifndef IBSHIFT
      32  # define IBSHIFT 16
      33  #endif
      34  
      35  #if defined(__sparc__)		\
      36   || defined(__powerpc__)	\
      37   || defined(__powerpc64__)	\
      38   || defined(__alpha__)		\
      39   || defined(__mips__)		\
      40   || defined(__hppa__)
      41  # define IOCTL_CLASHED 0
      42  #else
      43  # define IOCTL_CLASHED 1
      44  #endif
      45  
      46  #define PRINT_FLAG(val_, f_) \
      47  	do { \
      48  		if ((val_ & f_)) { \
      49  			printf("%s%s", sep, #f_); \
      50  			val_ &= ~f_; \
      51  			sep = "|"; \
      52  		} \
      53  	} while (0)
      54  
      55  extern int ioctl (int __fd, unsigned long int __request, ...);
      56  
      57  static void
      58  print_iflag(unsigned int iflag)
      59  {
      60  	const char *sep = "";
      61  
      62  	PRINT_FLAG(iflag, IGNBRK);
      63  	PRINT_FLAG(iflag, BRKINT);
      64  	PRINT_FLAG(iflag, IGNPAR);
      65  	PRINT_FLAG(iflag, PARMRK);
      66  	PRINT_FLAG(iflag, INPCK);
      67  	PRINT_FLAG(iflag, ISTRIP);
      68  	PRINT_FLAG(iflag, INLCR);
      69  	PRINT_FLAG(iflag, IGNCR);
      70  	PRINT_FLAG(iflag, ICRNL);
      71  	PRINT_FLAG(iflag, IUCLC);
      72  	PRINT_FLAG(iflag, IXON);
      73  	PRINT_FLAG(iflag, IXANY);
      74  	PRINT_FLAG(iflag, IXOFF);
      75  	PRINT_FLAG(iflag, IMAXBEL);
      76  	PRINT_FLAG(iflag, IUTF8);
      77  	if (iflag)
      78  		printf("%s%#x", sep, iflag);
      79  }
      80  
      81  static void
      82  print_oflag(unsigned int oflag)
      83  {
      84  	const char *sep = "";
      85  
      86  	static struct {
      87  		tcflag_t val;
      88  		const char *prefix;
      89  		unsigned int max_val;
      90  	} vals[] = {
      91  		{ NLDLY,  "NL",
      92  #if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
      93  			3
      94  #else
      95  			1
      96  #endif
      97  			},
      98  		{ CRDLY,  "CR",  3 },
      99  		{ TABDLY, "TAB", 3 },
     100  		{ BSDLY,  "BS",  1 },
     101  		{ VTDLY,  "VT",  1 },
     102  		{ FFDLY,  "FF",  1 },
     103  	};
     104  
     105  	for (unsigned int i = 0; i < ARRAY_SIZE(vals); i++) {
     106  		int val = (oflag & vals[i].val) /
     107  			(vals[i].val / vals[i].max_val);
     108  #if !defined __alpha__
     109  		if (i == 2 && val == 3) /* XTABS */
     110  			printf("XTABS|");
     111  		else
     112  #endif
     113  			printf("%s%u|", vals[i].prefix, val);
     114  		oflag &= ~vals[i].val;
     115  	}
     116  
     117  	sep = "";
     118  	PRINT_FLAG(oflag, OPOST);
     119  	PRINT_FLAG(oflag, OLCUC);
     120  	PRINT_FLAG(oflag, ONLCR);
     121  	PRINT_FLAG(oflag, OCRNL);
     122  	PRINT_FLAG(oflag, ONOCR);
     123  	PRINT_FLAG(oflag, ONLRET);
     124  	PRINT_FLAG(oflag, OFILL);
     125  	PRINT_FLAG(oflag, OFDEL);
     126  #ifdef PAGEOUT
     127  	PRINT_FLAG(oflag, PAGEOUT);
     128  #endif
     129  #ifdef WRAP
     130  	PRINT_FLAG(oflag, WRAP);
     131  #endif
     132  	if (oflag)
     133  		printf("%s%#x", sep, oflag);
     134  }
     135  
     136  static void
     137  print_cflag(unsigned int cflag)
     138  {
     139  	const char *sep = "";
     140  
     141  	printxval(baud_options, cflag & CBAUD, "B???");
     142  	printf("|");
     143  #if defined IBSHIFT && defined CIBAUD
     144  	if (cflag & CIBAUD) {
     145  		printxval(baud_options, (cflag & CIBAUD) >> IBSHIFT, "B???");
     146  		printf("<<IBSHIFT|");
     147  	}
     148  	cflag &= ~CIBAUD;
     149  #endif
     150  	switch (cflag & CSIZE) {
     151  	case CS5:
     152  		printf("CS5|");
     153  		break;
     154  	case CS6:
     155  		printf("CS6|");
     156  		break;
     157  	case CS7:
     158  		printf("CS7|");
     159  		break;
     160  	case CS8:
     161  		printf("CS8|");
     162  		break;
     163  	}
     164  	cflag &= ~(CBAUD | CSIZE);
     165  
     166  	PRINT_FLAG(cflag, CSTOPB);
     167  	PRINT_FLAG(cflag, CREAD);
     168  	PRINT_FLAG(cflag, PARENB);
     169  	PRINT_FLAG(cflag, PARODD);
     170  	PRINT_FLAG(cflag, HUPCL);
     171  	PRINT_FLAG(cflag, CLOCAL);
     172  #ifdef CTVB
     173  	PRINT_FLAG(cflag, CTVB);
     174  #endif
     175  #ifdef CMSPAR
     176  	PRINT_FLAG(cflag, CMSPAR);
     177  #endif
     178  #ifdef CRTSCTS
     179  	PRINT_FLAG(cflag, CRTSCTS);
     180  #endif
     181  	if (cflag)
     182  		printf("%s%#x", sep, cflag);
     183  }
     184  
     185  static void
     186  print_lflag(unsigned int lflag)
     187  {
     188  	const char *sep = "";
     189  
     190  	PRINT_FLAG(lflag, ISIG);
     191  	PRINT_FLAG(lflag, ICANON);
     192  	PRINT_FLAG(lflag, XCASE);
     193  	PRINT_FLAG(lflag, ECHO);
     194  	PRINT_FLAG(lflag, ECHOE);
     195  	PRINT_FLAG(lflag, ECHOK);
     196  	PRINT_FLAG(lflag, ECHONL);
     197  	PRINT_FLAG(lflag, NOFLSH);
     198  	PRINT_FLAG(lflag, IEXTEN);
     199  	PRINT_FLAG(lflag, ECHOCTL);
     200  	PRINT_FLAG(lflag, ECHOPRT);
     201  	PRINT_FLAG(lflag, ECHOKE);
     202  	PRINT_FLAG(lflag, FLUSHO);
     203  	PRINT_FLAG(lflag, PENDIN);
     204  	PRINT_FLAG(lflag, TOSTOP);
     205  #ifdef EXTPROC
     206  	PRINT_FLAG(lflag, EXTPROC);
     207  #endif
     208  #ifdef DEFECHO
     209  	PRINT_FLAG(lflag, DEFECHO);
     210  #endif
     211  	if (lflag)
     212  		printf("%s%#x", sep, lflag);
     213  }
     214  
     215  static void
     216  print_flags(unsigned int iflag, unsigned int oflag,
     217  	    unsigned int cflag, unsigned int lflag)
     218  {
     219  	printf("c_iflag=");
     220  	print_iflag(iflag);
     221  	printf(", c_oflag=");
     222  	print_oflag(oflag);
     223  	printf(", c_cflag=");
     224  	print_cflag(cflag);
     225  	printf(", c_lflag=");
     226  	print_lflag(lflag);
     227  }
     228  
     229  #define cc_def_(cc_) \
     230  	[cc_] = #cc_
     231  
     232  #if VERBOSE
     233  static void
     234  print_termios_cc(const cc_t *ccs, size_t size, bool tios)
     235  {
     236  	static const char * const cc_tio_names[] = {
     237  # if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     238  		cc_def_(_VMIN),
     239  		cc_def_(_VTIME),
     240  		cc_def_(_VINTR),
     241  		cc_def_(_VQUIT),
     242  		cc_def_(_VERASE),
     243  		cc_def_(_VKILL),
     244  		cc_def_(_VEOF),
     245  		cc_def_(_VEOL),
     246  		cc_def_(_VEOL2),
     247  		cc_def_(_VSWTC),
     248  # endif
     249  	};
     250  
     251  	static const char * const cc_tios_names[] = {
     252  		cc_def_(VMIN),
     253  		cc_def_(VTIME),
     254  
     255  		cc_def_(VINTR),
     256  		cc_def_(VQUIT),
     257  		cc_def_(VERASE),
     258  		cc_def_(VKILL),
     259  		cc_def_(VEOL2),
     260  		cc_def_(VSWTC),
     261  		cc_def_(VSTART),
     262  		cc_def_(VSTOP),
     263  		cc_def_(VSUSP),
     264  		cc_def_(VREPRINT),
     265  		cc_def_(VDISCARD),
     266  		cc_def_(VWERASE),
     267  		cc_def_(VLNEXT),
     268  # ifndef __sparc__ /* on sparc VMIN == VEOF and VTIME == VEOL */
     269  		cc_def_(VEOF),
     270  		cc_def_(VEOL),
     271  # endif
     272  # ifdef VDSUSP
     273  		cc_def_(VDSUSP),
     274  # endif
     275  	};
     276  
     277  	printf("c_cc=[");
     278  
     279  	for (size_t i = 0; i < size; i++) {
     280  		bool has_name = tios ?
     281  			(i < ARRAY_SIZE(cc_tios_names)) && cc_tios_names[i] :
     282  # if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     283  			(i < ARRAY_SIZE(cc_tio_names)) && cc_tio_names[i];
     284  # else
     285  			false;
     286  # endif
     287  		const char *name = has_name ?
     288  			(tios ? cc_tios_names : cc_tio_names)[i] : "";
     289  
     290  		if (has_name)
     291  			printf("%s[%s]=%#hhx", i ? ", " : "", name, ccs[i]);
     292  		else
     293  			printf("%s[%zu]=%#hhx", i ? ", " : "", i, ccs[i]);
     294  	}
     295  
     296  	printf("]");
     297  }
     298  #endif /* VERBOSE */
     299  
     300  #ifdef HAVE_STRUCT_TERMIOS2
     301  static void
     302  print_termios2(void *tios_ptr)
     303  {
     304  	struct termios2 *tios = tios_ptr;
     305  
     306  	printf("{");
     307  	print_flags(tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag);
     308  	printf(", ");
     309  
     310  # if VERBOSE
     311  	printf("c_line=");
     312  	printxval(term_line_discs, zero_extend_signed_to_ull(tios->c_line),
     313  		  "N_???");
     314  	printf(", ");
     315  
     316  	print_termios_cc(tios->c_cc, sizeof(tios->c_cc), true);
     317  
     318  	printf(", c_ispeed=%u, c_ospeed=%u", tios->c_ispeed, tios->c_ospeed);
     319  # else /* !VERBOSE */
     320  	printf("...");
     321  # endif /* VERBOSE */
     322  
     323  	printf("}");
     324  }
     325  #endif
     326  
     327  static void
     328  print_termios(void *tios_ptr)
     329  {
     330  	struct termios *tios = tios_ptr;
     331  
     332  	printf("{");
     333  	print_flags(tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag);
     334  	printf(", ");
     335  
     336  #if VERBOSE
     337  	printf("c_line=");
     338  	printxval(term_line_discs, zero_extend_signed_to_ull(tios->c_line),
     339  		  "N_???");
     340  	printf(", ");
     341  
     342  	print_termios_cc(tios->c_cc, sizeof(tios->c_cc), true);
     343  
     344  # ifdef HAVE_STRUCT_TERMIOS_C_ISPEED
     345  	printf(", c_ispeed=%u", tios->c_ispeed);
     346  # endif
     347  # ifdef HAVE_STRUCT_TERMIOS_C_OSPEED
     348  	printf(", c_ospeed=%u", tios->c_ospeed);
     349  # endif
     350  #else /* !VERBOSE */
     351  	printf("...");
     352  #endif /* VERBOSE */
     353  
     354  	printf("}");
     355  }
     356  
     357  static void
     358  print_termio(void *tios_ptr)
     359  {
     360  	struct termio *tios = tios_ptr;
     361  
     362  #if VERBOSE
     363  # if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     364  	const bool alpha = true;
     365  # else
     366  	const bool alpha = false;
     367  # endif
     368  #endif /* VERBOSE */
     369  
     370  	printf("{");
     371  	print_flags(tios->c_iflag, tios->c_oflag, tios->c_cflag, tios->c_lflag);
     372  
     373  	printf(", ");
     374  
     375  #if VERBOSE
     376  	printf("c_line=");
     377  	printxval(term_line_discs, zero_extend_signed_to_ull(tios->c_line),
     378  		  "N_???");
     379  	printf(", ");
     380  
     381  	print_termios_cc(tios->c_cc, MIN(NCC, sizeof(tios->c_cc)), !alpha);
     382  #else /* !VERBOSE */
     383  	printf("...");
     384  #endif /* VERBOSE */
     385  
     386  	printf("}");
     387  }
     388  
     389  static void
     390  do_ioctl(kernel_ulong_t cmd, const char *cmd_str, int fd,
     391  	 void (*printer)(void *data), kernel_ulong_t data_ptr, bool valid,
     392  	 bool write, const char *data_str, bool can_fail)
     393  {
     394  	long ret = 0;
     395  	long saved_errno = 0;
     396  	void *data = (void *) (uintptr_t) data_ptr;
     397  
     398  	if (!write) {
     399  		ret = ioctl(fd, cmd, data_ptr);
     400  		saved_errno = errno;
     401  	}
     402  
     403  	printf("ioctl(%d, %s, ", fd, cmd_str);
     404  
     405  	if (valid && !ret) {
     406  		if (data_str)
     407  			printf("%s", data_str);
     408  		else
     409  			printer(data);
     410  	} else {
     411  		if (data)
     412  			printf("%#llx", (unsigned long long) data_ptr);
     413  		else
     414  			printf("NULL");
     415  	}
     416  
     417  	if (write) {
     418  		ret = ioctl(fd, cmd, data_ptr);
     419  
     420  		if (valid && ret && !can_fail)
     421  			perror_msg_and_fail("ioctl(%d, %#llx, %#llx) = -1",
     422  					    fd, (unsigned long long) cmd,
     423  					    (unsigned long long) data_ptr);
     424  	} else {
     425  		errno = saved_errno;
     426  	}
     427  
     428  	printf(") = %s\n", sprintrc(ret));
     429  
     430  }
     431  
     432  #ifdef HAVE_STRUCT_TERMIOS2
     433  static const char *
     434  setup_termios2(void *tios_ptr, int variant)
     435  {
     436  	struct termios2 *tios = tios_ptr;
     437  
     438  	switch (variant) {
     439  	case 0:
     440  		fill_memory(tios, sizeof(*tios));
     441  		return NULL;
     442  
     443  	case 1:
     444  		fill_memory_ex(tios, sizeof(*tios), 0xA5, 0x5A);
     445  		return NULL;
     446  
     447  	case 2:
     448  		memset(tios, 0, sizeof(*tios));
     449  
     450  		tios->c_iflag = IGNBRK|IUTF8|0xdead0000;
     451  		tios->c_oflag = NL0|CR2|XTABS|BS0|VT1|FF0|OPOST|ONLCR|OFILL|
     452  # ifdef PAGEOUT
     453  				PAGEOUT|
     454  # endif
     455  				0xbad00000;
     456  		tios->c_cflag = B75
     457  # if defined IBSHIFT && defined CIBAUD
     458  			|(B57600<<IBSHIFT)
     459  # endif
     460  			|CS6|CSTOPB|
     461  # ifdef CTVB
     462  				CTVB|
     463  # endif
     464  # ifdef CMSPAR
     465  				CMSPAR|
     466  # endif
     467  				0;
     468  		tios->c_lflag = ISIG|ECHOE|FLUSHO|
     469  # ifdef DEFECHO
     470  				DEFECHO|
     471  # endif
     472  # if defined __alpha__ || defined __powerpc__ || defined __powerpc64__ || defined __sparc__
     473  				0xf0f0000
     474  # else
     475  				0xfee00000
     476  # endif
     477  				;
     478  
     479  		tios->c_line = N_IRDA;
     480  
     481  		tios->c_cc[VTIME] = 0xa0;
     482  		tios->c_cc[VMIN] = 0x89;
     483  		tios->c_cc[VLNEXT] = 0xff;
     484  		tios->c_cc[VSWTC] = 0x2a;
     485  
     486  		tios->c_ispeed = 3141592653U;
     487  		tios->c_ospeed = 2718281828U;
     488  
     489  		return "{c_iflag=IGNBRK|IUTF8|0xdead0000, "
     490  		       "c_oflag=NL0|CR2|"
     491  # ifdef __alpha__
     492  #  if TAB3 == XTABS
     493  		       "TAB3"
     494  #  else
     495  		       "TAB0"
     496  #  endif
     497  # else /* !__alpha__ */
     498  		       "XTABS"
     499  # endif
     500  		       "|BS0|VT1|FF0|OPOST|ONLCR|OFILL|"
     501  # ifdef PAGEOUT
     502  		       "PAGEOUT|"
     503  # endif
     504  # if defined __alpha__ && XTABS != TAB3
     505  		       "0xbad40000, "
     506  # else
     507  		       "0xbad00000, "
     508  # endif
     509  		       "c_cflag=B75"
     510  # if defined IBSHIFT && defined CIBAUD
     511  		       "|B57600<<IBSHIFT"
     512  # endif
     513  		       "|CS6|CSTOPB"
     514  # ifdef CTVB
     515  		       "|CTVB"
     516  # endif
     517  # ifdef CMSPAR
     518  		       "|CMSPAR"
     519  # endif
     520  		       ", "
     521  		       "c_lflag=ISIG|ECHOE|FLUSHO|"
     522  # ifdef __sparc__
     523  		       "EXTPROC|"
     524  # endif
     525  # ifdef DEFECHO
     526  		       "DEFECHO|"
     527  # endif
     528  # if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     529  		       "0xf0f0000, "
     530  # elif defined __sparc__
     531  		       "0xf0e0000, "
     532  # else
     533  		       "0xfee00000, "
     534  # endif
     535  # if VERBOSE
     536  		       "c_line=N_IRDA, "
     537  #  if defined __alpha__
     538  		       "c_cc=[[VEOF]=0, [VEOL]=0, [VEOL2]=0, "
     539  		       "[VERASE]=0, [VWERASE]=0, [VKILL]=0, "
     540  		       "[VREPRINT]=0x89, [VSWTC]=0x2a, [VINTR]=0, "
     541  		       "[VQUIT]=0, [VSUSP]=0, [11]=0, [VSTART]=0, "
     542  		       "[VSTOP]=0, [VLNEXT]=0xff, [VDISCARD]=0, "
     543  		       "[VMIN]=0x89, [VTIME]=0xa0, [18]=0]"
     544  #  elif defined __mips__
     545  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     546  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     547  		       "[VEOL2]=0, [VSWTC]=0x2a, [VSTART]=0, "
     548  		       "[VSTOP]=0, [VSUSP]=0, [11]=0, "
     549  		       "[VREPRINT]=0, [VDISCARD]=0, [VWERASE]=0, "
     550  		       "[VLNEXT]=0xff, [VEOF]=0, [VEOL]=0, [18]=0, "
     551  		       "[19]=0, [20]=0, [21]=0, [22]=0]"
     552  #  elif defined __sparc__
     553  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     554  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     555  		       "[VEOL2]=0, [VSWTC]=0x2a, [VSTART]=0, "
     556  		       "[VSTOP]=0, [VSUSP]=0, [VDSUSP]=0, "
     557  		       "[VREPRINT]=0, [VDISCARD]=0, [VWERASE]=0, "
     558  		       "[VLNEXT]=0xff, [16]=0, [17]=0, [18]=0]"
     559  #  else
     560  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     561  		       "[VKILL]=0, [VEOF]=0, [VTIME]=0xa0, "
     562  		       "[VMIN]=0x89, [VSWTC]=0x2a, [VSTART]=0, "
     563  		       "[VSTOP]=0, [VSUSP]=0, [VEOL]=0, [VREPRINT]=0, "
     564  		       "[VDISCARD]=0, [VWERASE]=0, [VLNEXT]=0xff, "
     565  		       "[VEOL2]=0, [17]=0, [18]=0]"
     566  #  endif
     567  		       ", c_ispeed=3141592653, c_ospeed=2718281828"
     568  # else /* !VERBOSE */
     569  		       "..."
     570  # endif /* VERBOSE */
     571  		       "}";
     572  	}
     573  
     574  	return NULL;
     575  }
     576  #endif
     577  
     578  static const char *
     579  setup_termios(void *tios_ptr, int variant)
     580  {
     581  	struct termios *tios = tios_ptr;
     582  
     583  	switch (variant) {
     584  	case 0:
     585  		fill_memory(tios, sizeof(*tios));
     586  		return NULL;
     587  
     588  	case 1:
     589  		fill_memory_ex(tios, sizeof(*tios), 0xA5, 0x5A);
     590  		return NULL;
     591  
     592  	case 2:
     593  		memset(tios, 0, sizeof(*tios));
     594  
     595  		tios->c_iflag = IGNBRK|IUTF8|0xdead0000;
     596  		tios->c_oflag = NL0|CR2|XTABS|BS0|VT1|FF0|OPOST|ONLCR|OFILL|
     597  #ifdef PAGEOUT
     598  				PAGEOUT|
     599  #endif
     600  				0xbad00000;
     601  		tios->c_cflag = B75
     602  #if defined IBSHIFT && defined CIBAUD
     603  			|(B57600<<IBSHIFT)
     604  #endif
     605  			|CS6|CSTOPB|
     606  #ifdef CTVB
     607  				CTVB|
     608  #endif
     609  #ifdef CMSPAR
     610  				CMSPAR|
     611  #endif
     612  				0;
     613  		tios->c_lflag = ISIG|ECHOE|FLUSHO|
     614  #ifdef DEFECHO
     615  				DEFECHO|
     616  #endif
     617  #if defined __alpha__ || defined __powerpc__ || defined __powerpc64__ || defined __sparc__
     618  				0xf0f0000
     619  #else
     620  				0xfee00000
     621  #endif
     622  				;
     623  
     624  		tios->c_line = N_AX25;
     625  
     626  		tios->c_cc[VTIME] = 0xa0;
     627  		tios->c_cc[VMIN] = 0x89;
     628  		tios->c_cc[VLNEXT] = 0xff;
     629  		tios->c_cc[VSWTC] = 0x2a;
     630  
     631  #ifdef HAVE_STRUCT_TERMIOS_C_ISPEED
     632  		tios->c_ispeed = 3141592653U;
     633  #endif
     634  #ifdef HAVE_STRUCT_TERMIOS_C_OSPEED
     635  		tios->c_ospeed = 2718281828U;
     636  #endif
     637  
     638  		return "{c_iflag=IGNBRK|IUTF8|0xdead0000, "
     639  		       "c_oflag=NL0|CR2|"
     640  #ifdef __alpha__
     641  # if TAB3 == XTABS
     642  		       "TAB3"
     643  # else
     644  		       "TAB0"
     645  # endif
     646  #else /* !__alpha__ */
     647  		       "XTABS"
     648  #endif
     649  		       "|BS0|VT1|FF0|OPOST|ONLCR|OFILL|"
     650  #ifdef PAGEOUT
     651  		       "PAGEOUT|"
     652  #endif
     653  #if defined __alpha__ && XTABS != TAB3
     654  		       "0xbad40000, "
     655  #else
     656  		       "0xbad00000, "
     657  #endif
     658  		       "c_cflag=B75"
     659  #if defined IBSHIFT && defined CIBAUD
     660  		       "|B57600<<IBSHIFT"
     661  #endif
     662  		       "|CS6|CSTOPB"
     663  #ifdef CTVB
     664  		       "|CTVB"
     665  #endif
     666  #ifdef CMSPAR
     667  		       "|CMSPAR"
     668  #endif
     669  		       ", "
     670  		       "c_lflag=ISIG|ECHOE|FLUSHO|"
     671  #ifdef __sparc__
     672  		       "EXTPROC|"
     673  #endif
     674  #ifdef DEFECHO
     675  		       "DEFECHO|"
     676  #endif
     677  #if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     678  		       "0xf0f0000, "
     679  #elif defined __sparc__
     680  		       "0xf0e0000, "
     681  #else
     682  		       "0xfee00000, "
     683  #endif
     684  #if VERBOSE
     685  		       "c_line=N_AX25, "
     686  # if defined __alpha__
     687  		       "c_cc=[[VEOF]=0, [VEOL]=0, [VEOL2]=0, "
     688  		       "[VERASE]=0, [VWERASE]=0, [VKILL]=0, "
     689  		       "[VREPRINT]=0x89, [VSWTC]=0x2a, [VINTR]=0, "
     690  		       "[VQUIT]=0, [VSUSP]=0, [11]=0, [VSTART]=0, "
     691  		       "[VSTOP]=0, [VLNEXT]=0xff, [VDISCARD]=0, "
     692  		       "[VMIN]=0x89, [VTIME]=0xa0, [18]=0]"
     693  # elif defined __mips__
     694  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     695  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     696  		       "[VEOL2]=0, [VSWTC]=0x2a, [VSTART]=0, "
     697  		       "[VSTOP]=0, [VSUSP]=0, [11]=0, "
     698  		       "[VREPRINT]=0, [VDISCARD]=0, [VWERASE]=0, "
     699  		       "[VLNEXT]=0xff, [VEOF]=0, [VEOL]=0, [18]=0, "
     700  		       "[19]=0, [20]=0, [21]=0, [22]=0]"
     701  # elif defined __powerpc__ || defined __powerpc64__
     702  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     703  		       "[VKILL]=0, [VEOF]=0, [VMIN]=0x89, "
     704  		       "[VEOL]=0, [VTIME]=0xa0, [VEOL2]=0, "
     705  		       "[VSWTC]=0x2a, [VWERASE]=0, [VREPRINT]=0, "
     706  		       "[VSUSP]=0, [VSTART]=0, [VSTOP]=0, "
     707  		       "[VLNEXT]=0xff, [VDISCARD]=0, [17]=0, [18]=0]"
     708  # elif defined __sparc__
     709  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     710  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     711  		       "[VEOL2]=0, [VSWTC]=0x2a, [VSTART]=0, "
     712  		       "[VSTOP]=0, [VSUSP]=0, [VDSUSP]=0, "
     713  		       "[VREPRINT]=0, [VDISCARD]=0, [VWERASE]=0, "
     714  		       "[VLNEXT]=0xff, [16]=0]"
     715  # else
     716  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     717  		       "[VKILL]=0, [VEOF]=0, [VTIME]=0xa0, "
     718  		       "[VMIN]=0x89, [VSWTC]=0x2a, [VSTART]=0, "
     719  		       "[VSTOP]=0, [VSUSP]=0, [VEOL]=0, [VREPRINT]=0, "
     720  		       "[VDISCARD]=0, [VWERASE]=0, [VLNEXT]=0xff, "
     721  		       "[VEOL2]=0, [17]=0, [18]=0]"
     722  # endif
     723  # ifdef HAVE_STRUCT_TERMIOS_C_ISPEED
     724  		       ", c_ispeed=3141592653"
     725  # endif
     726  # ifdef HAVE_STRUCT_TERMIOS_C_OSPEED
     727  		       ", c_ospeed=2718281828"
     728  # endif
     729  #else /* !VERBOSE */
     730  		       "..."
     731  #endif /* VERBOSE */
     732  		       "}";
     733  	}
     734  
     735  	return NULL;
     736  }
     737  
     738  static const char *
     739  setup_termio(void *tios_ptr, int variant)
     740  {
     741  	struct termio *tios = tios_ptr;
     742  
     743  	switch (variant) {
     744  	case 0:
     745  		fill_memory(tios, sizeof(*tios));
     746  		return NULL;
     747  
     748  	case 1:
     749  		fill_memory_ex(tios, sizeof(*tios), 0xA5, 0x5A);
     750  		return NULL;
     751  
     752  	case 2:
     753  		memset(tios, 0, sizeof(*tios));
     754  
     755  		tios->c_iflag = (unsigned short) (IGNBRK|IUTF8);
     756  		tios->c_oflag = (unsigned short) (NL0|CR2|XTABS|BS0|VT1|FF0|
     757  				OPOST|ONLCR|OFILL|
     758  #ifdef PAGEOUT
     759  				PAGEOUT|
     760  #endif
     761  				0);
     762  		tios->c_cflag = (unsigned short) (B75|CS6|CSTOPB);
     763  		tios->c_lflag = (unsigned short) (ISIG|ECHOE|FLUSHO|
     764  #ifdef DEFECHO
     765  				DEFECHO|
     766  #endif
     767  				0);
     768  
     769  		tios->c_line = 234;
     770  
     771  #if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     772  		tios->c_cc[_VTIME] = 0xa0;
     773  		tios->c_cc[_VMIN] = 0x89;
     774  		tios->c_cc[_VSWTC] = 0x2a;
     775  #else
     776  		tios->c_cc[VTIME] = 0xa0;
     777  		tios->c_cc[VMIN] = 0x89;
     778  		tios->c_cc[VSWTC] = 0x2a;
     779  #endif
     780  
     781  		return "{c_iflag=IGNBRK|IUTF8, "
     782  		       "c_oflag=NL0|CR2|"
     783  #ifdef __alpha__
     784  # if TAB3 == XTABS
     785  		       "TAB3"
     786  # else
     787  		       "TAB0"
     788  # endif
     789  #else
     790  		       "XTABS"
     791  #endif
     792  		       "|BS0"
     793  #if defined __alpha__ || defined __powerpc__ || defined __powerpc64__
     794  		       "|VT0"
     795  #else
     796  		       "|VT1"
     797  #endif
     798  		       "|FF0|OPOST|ONLCR|OFILL"
     799  #if defined PAGEOUT && !defined __sparc__
     800  		       "|PAGEOUT"
     801  #endif
     802  		       ", "
     803  		       "c_cflag=B75|CS6|CSTOPB, "
     804  		       "c_lflag=ISIG|ECHOE"
     805  /* the value is too big for termio lflag */
     806  #if !(defined __alpha__ || defined __powerpc__ || defined __powerpc64__)
     807  		       "|FLUSHO"
     808  #endif
     809  #ifdef DEFECHO
     810  		       "|DEFECHO"
     811  #endif
     812  		       ", "
     813  #if VERBOSE
     814  		       "c_line=0xea /* N_??? */, "
     815  # if defined __alpha__
     816  		       "c_cc=[[_VEOF]=0, [_VEOL]=0, [_VEOL2]=0, "
     817  		       "[_VERASE]=0, [_VWERASE]=0, [_VKILL]=0, "
     818  		       "[_VREPRINT]=0x89, [_VSWTC]=0x2a]"
     819  # elif defined __mips__
     820  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     821  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     822  		       "[VEOL2]=0, [VSWTC]=0x2a]"
     823  # elif defined __powerpc__ || defined __powerpc64__
     824  		       "c_cc=[[_VINTR]=0, [_VQUIT]=0, [_VERASE]=0, "
     825  		       "[_VKILL]=0, [_VEOF]=0, [_VMIN]=0x89, "
     826  		       "[_VEOL]=0, [_VTIME]=0xa0, [_VEOL2]=0, "
     827  		       "[_VSWTC]=0x2a]"
     828  # elif defined __sparc__
     829  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     830  		       "[VKILL]=0, [VMIN]=0x89, [VTIME]=0xa0, "
     831  		       "[VEOL2]=0, [VSWTC]=0x2a]"
     832  # else
     833  		       "c_cc=[[VINTR]=0, [VQUIT]=0, [VERASE]=0, "
     834  		       "[VKILL]=0, [VEOF]=0, [VTIME]=0xa0, "
     835  		       "[VMIN]=0x89, [VSWTC]=0x2a]"
     836  # endif
     837  #else /* !VERBOSE */
     838  		       "..."
     839  #endif
     840  		       "}";
     841  	}
     842  
     843  	return NULL;
     844  }
     845  
     846  int
     847  main(void)
     848  {
     849  	int ret;
     850  
     851  	struct termio *tio = tail_alloc(sizeof(*tio));
     852  	struct termios *tios1 = tail_alloc(sizeof(*tios1));
     853  #ifdef HAVE_STRUCT_TERMIOS2
     854  	struct termios2 *tios2 = tail_alloc(sizeof(*tios2));
     855  #endif
     856  
     857  	struct {
     858  		struct {
     859  			kernel_ulong_t cmd;
     860  			const char *cmd_str;
     861  			bool write;
     862  			bool can_fail;
     863  			bool pass_invalid_fd;
     864  		} cmds[9];
     865  		struct {
     866  			kernel_ulong_t data;
     867  			const char *data_str;
     868  			bool valid;
     869  		} args[4]; /* The last one should be valid */
     870  		void (*printer)(void *data);
     871  		const char * (*setup)(void *data, int variant);
     872  		unsigned int setup_variants;
     873  	} checks[] = {
     874  #ifdef HAVE_STRUCT_TERMIOS2
     875  		{
     876  			{
     877  				{ ARG_STR(TCSETS2),  true },
     878  				{ ARG_STR(TCSETSW2), true },
     879  				{ ARG_STR(TCSETSF2), true },
     880  				{ ARG_STR(TCGETS2),  false },
     881  			},
     882  			{
     883  				{ (uintptr_t) ARG_STR(NULL), false },
     884  				{ (uintptr_t) (tios2 + 1), NULL, false },
     885  				{ (uintptr_t) tios2 + 4, NULL, false },
     886  				{ (uintptr_t) tios2, NULL, true },
     887  			},
     888  			print_termios2, setup_termios2, 3
     889  		},
     890  #endif
     891  		{
     892  			{
     893  				/*
     894  				 * If the fd is valid and points to a tty,
     895  				 * the potential ioctl command collision is resolved.
     896  				 */
     897  				{ ARG_STR(TCSETS),  true },
     898  				{ ARG_STR(TCSETSW), true },
     899  				{ ARG_STR(TCSETSF), true },
     900  
     901  				/*
     902  				 * If the fd is invalid, it is impossible
     903  				 * to distinguish the overlapping ioctl commands.
     904  				 */
     905  				{ TCSETS,
     906  #if IOCTL_CLASHED
     907  					"SNDCTL_TMR_START or "
     908  #endif
     909  					"TCSETS", true, true, true },
     910  				{ TCSETSW,
     911  #if IOCTL_CLASHED
     912  					"SNDCTL_TMR_STOP or "
     913  #endif
     914  					"TCSETSW", true, true, true },
     915  				{ TCSETSF,
     916  #if IOCTL_CLASHED
     917  					"SNDCTL_TMR_CONTINUE or "
     918  #endif
     919  					"TCSETSF", true, true, true },
     920  
     921  				{ ARG_STR(TCGETS),  false },
     922  				{ ARG_STR(TIOCSLCKTRMIOS), true,  true },
     923  				{ ARG_STR(TIOCGLCKTRMIOS), false, true },
     924  			},
     925  			{
     926  				{ (uintptr_t) ARG_STR(NULL), false },
     927  				{ (uintptr_t) (tios1 + 1), NULL, false },
     928  				{ (uintptr_t) tios1 + 4, NULL, false },
     929  				{ (uintptr_t) tios1, NULL, true },
     930  			},
     931  			print_termios, setup_termios, 3
     932  		},
     933  		{
     934  			{
     935  				{ ARG_STR(TCSETA),  true },
     936  				{ ARG_STR(TCSETAW), true },
     937  				{ ARG_STR(TCSETAF), true },
     938  				{ ARG_STR(TCGETA),  false },
     939  			},
     940  			{
     941  				{ (uintptr_t) ARG_STR(NULL), false },
     942  				{ (uintptr_t) (tio + 1), NULL, false },
     943  				{ (uintptr_t) tio + 4, NULL, false },
     944  				{ (uintptr_t) tio, NULL, true },
     945  			},
     946  			print_termio, setup_termio, 3
     947  		},
     948  	};
     949  
     950  	static const char ptmx[] = "/dev/ptmx";
     951  	/*
     952  	 * The libc function is not available because <linux/fcntl.h>
     953  	 * is included instead of <fcntl.h>.
     954  	 */
     955  	ret = syscall(__NR_openat, -100, ptmx, O_RDWR|O_NOCTTY);
     956  	if (ret < 0)
     957  		perror_msg_and_skip("open: %s", ptmx);
     958  
     959  	for (size_t i = 0; i < ARRAY_SIZE(checks); i++) {
     960  		const char *last_arg_str = NULL;
     961  
     962  		for (size_t j = 0; j < ARRAY_SIZE(checks[0].cmds); j++) {
     963  			size_t k = 0, l = 0;
     964  			bool end = false;
     965  			bool write = checks[i].cmds[j].write;
     966  
     967  			if (!checks[i].cmds[j].cmd_str)
     968  				continue;
     969  
     970  			while (true) {
     971  				if (write && checks[i].args[k].valid)
     972  					last_arg_str = checks[i].setup(
     973  						(void *) (uintptr_t) (checks[i].args[k].data),
     974  						l);
     975  
     976  				do_ioctl(checks[i].cmds[j].cmd,
     977  					 checks[i].cmds[j].cmd_str,
     978  					 checks[i].cmds[j].pass_invalid_fd? -1: ret,
     979  					 checks[i].printer,
     980  					 checks[i].args[k].data,
     981  					 checks[i].args[k].valid,
     982  					 write, last_arg_str,
     983  					 checks[i].cmds[j].can_fail);
     984  
     985  				if (k < (ARRAY_SIZE(checks[0].args) - 1))
     986  					k++;
     987  				else if (write && (l < checks[i].setup_variants))
     988  					l++;
     989  				else if (!write && (l < 1))
     990  					l++;
     991  				else
     992  					end = true;
     993  
     994  				if (end)
     995  					break;
     996  			}
     997  		}
     998  	}
     999  
    1000  	puts("+++ exited with 0 +++");
    1001  
    1002  	return 0;
    1003  }