1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * 07/2001 Ported by Wayne Boyer
5 * 04/2002 Fixes by wjhuie
6 */
7 /*
8 * DESCRIPTION
9 * Testcase to check the errnos set by the ioctl(2) system call.
10 *
11 * ALGORITHM
12 * 1. EBADF: Pass an invalid fd to ioctl(fd, ..) and expect EBADF.
13 * 2. EFAULT: Pass an invalid address of arg in ioctl(fd, .., arg)
14 * 3. EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg)
15 * 4. ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg)
16 * 5. EFAULT: Pass a NULL address for termio
17 *
18 */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <termio.h>
24 #include <termios.h>
25 #include "tst_test.h"
26
27 #define INVAL_IOCTL 9999999
28
29 static int fd, fd_file;
30 static int bfd = -1;
31
32 static struct termio termio;
33
34 static struct tcase {
35 int *fd;
36 int request;
37 struct termio *s_tio;
38 int error;
39 } tcases[] = {
40 /* file descriptor is invalid */
41 {&bfd, TCGETA, &termio, EBADF},
42 /* termio address is invalid */
43 {&fd, TCGETA, (struct termio *)-1, EFAULT},
44 /* command is invalid */
45 /* This errno value was changed from EINVAL to ENOTTY
46 * by kernel commit 07d106d0 and bbb63c51
47 */
48 {&fd, INVAL_IOCTL, &termio, ENOTTY},
49 /* file descriptor is for a regular file */
50 {&fd_file, TCGETA, &termio, ENOTTY},
51 /* termio is NULL */
52 {&fd, TCGETA, NULL, EFAULT}
53 };
54
55 static char *device;
56
verify_ioctl(unsigned int i)57 static void verify_ioctl(unsigned int i)
58 {
59 TEST(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio));
60
61 if (TST_RET != -1) {
62 tst_res(TFAIL, "call succeeded unexpectedly");
63 return;
64 }
65
66 if (TST_ERR != tcases[i].error) {
67 tst_res(TFAIL | TTERRNO,
68 "failed unexpectedly; expected %s",
69 tst_strerrno(tcases[i].error));
70 return;
71 }
72
73 tst_res(TPASS | TTERRNO, "failed as expected");
74 }
75
setup(void)76 static void setup(void)
77 {
78 unsigned int i;
79
80 if (!device)
81 tst_brk(TBROK, "You must specify a tty device with -D option");
82
83 fd = SAFE_OPEN(device, O_RDWR, 0777);
84
85 if (tst_kvercmp(3, 7, 0) < 0) {
86 for (i = 0; i < ARRAY_SIZE(tcases); i++) {
87 if (tcases[i].request == INVAL_IOCTL)
88 tcases[i].error = EINVAL;
89 }
90 }
91
92 fd_file = SAFE_OPEN("x", O_CREAT, 0777);
93 }
94
cleanup(void)95 static void cleanup(void)
96 {
97 if (fd > 0)
98 SAFE_CLOSE(fd);
99
100 if (fd_file > 0)
101 SAFE_CLOSE(fd_file);
102 }
103
104 static struct tst_test test = {
105 .needs_root = 1,
106 .needs_tmpdir = 1,
107 .setup = setup,
108 .cleanup = cleanup,
109 .test = verify_ioctl,
110 .tcnt = ARRAY_SIZE(tcases),
111 .options = (struct tst_option[]) {
112 {"D:", &device, "-D <tty device> : for example, /dev/tty[0-9]"},
113 {}
114 }
115 };
116