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 = (TST_RET == tcase->exp_ret);
134 if (TST_RET < 0 || tcase->exp_ret < 0) {
135 ret &= (TST_ERR == 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 TST_RET, tst_strerrno(TST_ERR));
140 } else {
141 tst_res((ret ? TPASS : TFAIL),
142 "%s, expected: %d, got: %ld", tcase->desc,
143 tcase->exp_ret, TST_RET);
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