xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/ioctl/ioctl01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines Corp., 2001
4  * Copyright (c) 2020 Petr Vorel <[email protected]>
5  * Copyright (c) Linux Test Project, 2002-2023
6  * 07/2001 Ported by Wayne Boyer
7  * 04/2002 Fixes by wjhuie
8  */
9 
10 /*\
11  * [Description]
12  *
13  * Testcase to check the errnos set by the ioctl(2) system call.
14  *
15  * - EBADF: Pass an invalid fd to ioctl(fd, ...) and expect EBADF
16  * - EFAULT: Pass an invalid address of arg in ioctl(fd, ..., arg)
17  * - EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg)
18  * - ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg)
19  * - EFAULT: Pass a NULL address for termio
20  */
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <termios.h>
26 #include <pty.h>
27 #include "tst_test.h"
28 #include "lapi/ioctl.h"
29 
30 #define	INVAL_IOCTL	9999999
31 
32 static int amaster, aslave;
33 static int fd, fd_file;
34 static int bfd = -1;
35 
36 static struct termio termio;
37 static struct termios termios;
38 
39 static struct tcase {
40 	const char *desc;
41 	int *fd;
42 	int request;
43 	void *s_tio;
44 	int error;
45 } tcases[] = {
46 	{"File descriptor is invalid (termio)", &bfd, TCGETA, &termio, EBADF},
47 	{"File descriptor is invalid (termios)", &bfd, TCGETS, &termios, EBADF},
48 	{"Termio address is invalid", &fd, TCGETA, (struct termio *)-1, EFAULT},
49 	{"Termios address is invalid", &fd, TCGETS, (struct termios *)-1, EFAULT},
50 	/* This errno value was changed from EINVAL to ENOTTY
51 	 * by kernel commit 07d106d0 and bbb63c51
52 	 */
53 	{"Command is invalid", &fd, INVAL_IOCTL, &termio, ENOTTY},
54 	{"File descriptor is for a regular file (termio)", &fd_file, TCGETA, &termio, ENOTTY},
55 	{"File descriptor is for a regular file (termios)", &fd_file, TCGETS, &termios, ENOTTY},
56 	{"Termio is NULL", &fd, TCGETA, NULL, EFAULT},
57 	{"Termios is NULL", &fd, TCGETS, NULL, EFAULT}
58 };
59 
verify_ioctl(unsigned int i)60 static void verify_ioctl(unsigned int i)
61 {
62 	TST_EXP_FAIL(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio),
63 		     tcases[i].error, "%s", tcases[i].desc);
64 }
65 
setup(void)66 static void setup(void)
67 {
68 	if (openpty(&amaster, &aslave, NULL, NULL, NULL) < 0)
69 		tst_brk(TBROK | TERRNO, "unable to open pty");
70 
71 	fd = amaster;
72 	fd_file = SAFE_OPEN("x", O_CREAT, 0777);
73 }
74 
cleanup(void)75 static void cleanup(void)
76 {
77 	if (amaster > 0)
78 		SAFE_CLOSE(amaster);
79 	if (aslave > 0)
80 		SAFE_CLOSE(aslave);
81 	if (fd_file > 0)
82 		SAFE_CLOSE(fd_file);
83 }
84 
85 static struct tst_test test = {
86 	.needs_tmpdir = 1,
87 	.setup = setup,
88 	.cleanup = cleanup,
89 	.test = verify_ioctl,
90 	.tcnt = ARRAY_SIZE(tcases)
91 };
92