1 /*
2  *   Copyright (c) International Business Machines  Corp., 2001
3  *                 Linux Test Project, 2016
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;
17  */
18 
19 /*
20  * DESCRIPTION
21  *	Testcase to check the basic functionality of writev(2) system call.
22  *	Create IO vectors and attempt to writev various components of it.
23  */
24 
25 #include <errno.h>
26 #include <signal.h>
27 #include <sys/uio.h>
28 #include "tst_test.h"
29 
30 #define	CHUNK		64
31 #define	TESTFILE	"writev_data_file"
32 
33 static int valid_fd;
34 static int invalid_fd = -1;
35 static int pipe_fd[2];
36 
37 static char buf[CHUNK * 4];
38 
39 struct iovec iovec_badlen[] = {
40 	{ buf, -1 },
41 	{ buf + CHUNK, CHUNK },
42 	{ buf + CHUNK * 2, CHUNK },
43 };
44 
45 struct iovec iovec_simple[] = {
46 	{ buf, CHUNK },
47 };
48 
49 struct iovec iovec_zero_null[] = {
50 	{ buf, CHUNK },
51 	{ buf + CHUNK, 0 },
52 	{ NULL, 0 },
53 	{ NULL, 0 }
54 };
55 
56 struct testcase_t {
57 	const char *desc;
58 	int *pfd;
59 	struct iovec (*piovec)[];
60 	int iovcnt;
61 	int exp_ret;
62 	int exp_errno;
63 } testcases[] = {
64 	{
65 		.desc = "invalid iov_len",
66 		.pfd = &valid_fd,
67 		.piovec = &iovec_badlen,
68 		.iovcnt = ARRAY_SIZE(iovec_badlen),
69 		.exp_ret = -1,
70 		.exp_errno = EINVAL
71 	},
72 	{
73 		.desc = "invalid fd",
74 		.pfd = &invalid_fd,
75 		.piovec = &iovec_simple,
76 		.iovcnt = ARRAY_SIZE(iovec_simple),
77 		.exp_ret = -1,
78 		.exp_errno = EBADF
79 	},
80 	{
81 		.desc = "invalid iovcnt",
82 		.pfd = &valid_fd,
83 		.piovec = &iovec_simple,
84 		.iovcnt = -1,
85 		.exp_ret = -1,
86 		.exp_errno = EINVAL
87 	},
88 	{
89 		.desc = "zero iovcnt",
90 		.pfd = &valid_fd,
91 		.piovec = &iovec_simple,
92 		.iovcnt = 0,
93 		.exp_ret = 0,
94 	},
95 	{
96 		.desc = "NULL and zero length iovec",
97 		.pfd = &valid_fd,
98 		.piovec = &iovec_zero_null,
99 		.iovcnt = ARRAY_SIZE(iovec_zero_null),
100 		.exp_ret = CHUNK,
101 	},
102 	{
103 		.desc = "write to closed pipe",
104 		.pfd = &(pipe_fd[1]),
105 		.piovec = &iovec_simple,
106 		.iovcnt = ARRAY_SIZE(iovec_simple),
107 		.exp_ret = -1,
108 		.exp_errno = EPIPE,
109 	},
110 };
111 
setup(void)112 void setup(void)
113 {
114 	sigset_t block_mask;
115 
116 	sigemptyset(&block_mask);
117 	sigaddset(&block_mask, SIGPIPE);
118 	sigprocmask(SIG_BLOCK, &block_mask, NULL);
119 
120 	valid_fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, 0644);
121 
122 	SAFE_PIPE(pipe_fd);
123 	SAFE_CLOSE(pipe_fd[0]);
124 }
125 
test_writev(unsigned int i)126 static void test_writev(unsigned int i)
127 {
128 	struct testcase_t *tcase = &testcases[i];
129 	int ret;
130 
131 	TEST(writev(*(tcase->pfd), *(tcase->piovec), tcase->iovcnt));
132 
133 	ret = (TEST_RETURN == tcase->exp_ret);
134 	if (TEST_RETURN < 0 || tcase->exp_ret < 0) {
135 		ret &= (TEST_ERRNO == tcase->exp_errno);
136 		tst_res((ret ? TPASS : TFAIL),
137 			"%s, expected: %d (%s), got: %ld (%s)", tcase->desc,
138 			tcase->exp_ret, tst_strerrno(tcase->exp_errno),
139 			TEST_RETURN, tst_strerrno(TEST_ERRNO));
140 	} else {
141 		tst_res((ret ? TPASS : TFAIL),
142 			"%s, expected: %d, got: %ld", tcase->desc,
143 			tcase->exp_ret, TEST_RETURN);
144 	}
145 }
146 
147 static struct tst_test test = {
148 	.needs_tmpdir = 1,
149 	.setup = setup,
150 	.test = test_writev,
151 	.tcnt = ARRAY_SIZE(testcases),
152 };
153