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