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 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 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