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 }