1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * Linux Test Project, 2016
5 */
6
7 /*
8 * DESCRIPTION
9 * Testcase to check the basic functionality of writev(2) system call.
10 * Create IO vectors and attempt to writev various components of it.
11 */
12
13 #include <errno.h>
14 #include <signal.h>
15 #include <sys/uio.h>
16 #include "tst_test.h"
17
18 #define CHUNK 64
19 #define TESTFILE "writev_data_file"
20
21 static int valid_fd;
22 static int invalid_fd = -1;
23 static int pipe_fd[2];
24
25 static char buf[CHUNK * 4];
26
27 struct iovec iovec_badlen[] = {
28 { buf, -1 },
29 { buf + CHUNK, CHUNK },
30 { buf + CHUNK * 2, CHUNK },
31 };
32
33 struct iovec iovec_simple[] = {
34 { buf, CHUNK },
35 };
36
37 struct iovec iovec_zero_null[] = {
38 { buf, CHUNK },
39 { buf + CHUNK, 0 },
40 { NULL, 0 },
41 { NULL, 0 }
42 };
43
44 struct testcase_t {
45 const char *desc;
46 int *pfd;
47 struct iovec (*piovec)[];
48 int iovcnt;
49 int exp_ret;
50 int exp_errno;
51 } testcases[] = {
52 {
53 .desc = "invalid iov_len",
54 .pfd = &valid_fd,
55 .piovec = &iovec_badlen,
56 .iovcnt = ARRAY_SIZE(iovec_badlen),
57 .exp_ret = -1,
58 .exp_errno = EINVAL
59 },
60 {
61 .desc = "invalid fd",
62 .pfd = &invalid_fd,
63 .piovec = &iovec_simple,
64 .iovcnt = ARRAY_SIZE(iovec_simple),
65 .exp_ret = -1,
66 .exp_errno = EBADF
67 },
68 {
69 .desc = "invalid iovcnt",
70 .pfd = &valid_fd,
71 .piovec = &iovec_simple,
72 .iovcnt = -1,
73 .exp_ret = -1,
74 .exp_errno = EINVAL
75 },
76 {
77 .desc = "zero iovcnt",
78 .pfd = &valid_fd,
79 .piovec = &iovec_simple,
80 .iovcnt = 0,
81 .exp_ret = 0,
82 },
83 {
84 .desc = "NULL and zero length iovec",
85 .pfd = &valid_fd,
86 .piovec = &iovec_zero_null,
87 .iovcnt = ARRAY_SIZE(iovec_zero_null),
88 .exp_ret = CHUNK,
89 },
90 {
91 .desc = "write to closed pipe",
92 .pfd = &(pipe_fd[1]),
93 .piovec = &iovec_simple,
94 .iovcnt = ARRAY_SIZE(iovec_simple),
95 .exp_ret = -1,
96 .exp_errno = EPIPE,
97 },
98 };
99
setup(void)100 void setup(void)
101 {
102 sigset_t block_mask;
103
104 sigemptyset(&block_mask);
105 sigaddset(&block_mask, SIGPIPE);
106 sigprocmask(SIG_BLOCK, &block_mask, NULL);
107
108 valid_fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, 0644);
109
110 SAFE_PIPE(pipe_fd);
111 SAFE_CLOSE(pipe_fd[0]);
112 }
113
test_writev(unsigned int i)114 static void test_writev(unsigned int i)
115 {
116 struct testcase_t *tcase = &testcases[i];
117 int ret;
118
119 TEST(writev(*(tcase->pfd), *(tcase->piovec), tcase->iovcnt));
120
121 ret = (TST_RET == tcase->exp_ret);
122 if (TST_RET < 0 || tcase->exp_ret < 0) {
123 ret &= (TST_ERR == tcase->exp_errno);
124 tst_res((ret ? TPASS : TFAIL),
125 "%s, expected: %d (%s), got: %ld (%s)", tcase->desc,
126 tcase->exp_ret, tst_strerrno(tcase->exp_errno),
127 TST_RET, tst_strerrno(TST_ERR));
128 } else {
129 tst_res((ret ? TPASS : TFAIL),
130 "%s, expected: %d, got: %ld", tcase->desc,
131 tcase->exp_ret, TST_RET);
132 }
133 }
134
135 static struct tst_test test = {
136 .needs_tmpdir = 1,
137 .setup = setup,
138 .test = test_writev,
139 .tcnt = ARRAY_SIZE(testcases),
140 };
141