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 * 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
32static int amaster, aslave;
33static int fd, fd_file;
34static int bfd = -1;
35
36static struct termio termio;
37static struct termios termios;
38
39static 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
60static 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
66static 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
75static 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
85static 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