1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 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; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * write05.c 23 * 24 * DESCRIPTION 25 * Check the return value, and errnos of write(2) 26 * - when the file descriptor is invalid - EBADF 27 * - when the buf parameter is invalid - EFAULT 28 * - on an attempt to write to a pipe that is not open for reading - EPIPE 29 * 30 * ALGORITHM 31 * Attempt to write on a file with negative file descriptor, check for -1 32 * Attempt to write on a file with invalid buffer, check for -1 33 * Open a pipe and close the read end, attempt to write to the write 34 * end, check for -1. 35 * 36 * USAGE: <for command-line> 37 * write05 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 38 * where, -c n : Run n copies concurrently. 39 * -e : Turn on errno logging. 40 * -i n : Execute test n times. 41 * -I x : Execute test for x seconds. 42 * -P x : Pause for x seconds between iterations. 43 * -t : Turn on syscall timing. 44 * 45 * History 46 * 07/2001 John George 47 * -Ported 48 * 04/2002 wjhuie sigset cleanups 49 * 08/2007 Ricardo Salveti de Araujo <rsalveti (at) linux.vnet.ibm.com> 50 * - Closing the fd before removing the file 51 * 52 * Restrictions 53 * None 54 */ 55 #include <sys/types.h> 56 #include <sys/stat.h> 57 #include <fcntl.h> 58 #include <errno.h> 59 #include <stdio.h> 60 #include <sys/wait.h> 61 #include <sys/mman.h> 62 #include "test.h" 63 64 void setup(void); 65 void cleanup(void); 66 67 char *TCID = "write05"; 68 int TST_TOTAL = 1; 69 char filename[100]; 70 int fd; 71 72 char *bad_addr = 0; 73 74 int main(int argc, char **argv) 75 { 76 int lc; 77 78 char pbuf[BUFSIZ]; 79 int pipefildes[2]; 80 int status, pid; 81 82 tst_parse_opts(argc, argv, NULL, NULL); 83 84 /* global setup */ 85 setup(); 86 87 /* The following loop checks looping state if -i option given */ 88 for (lc = 0; TEST_LOOPING(lc); lc++) { 89 90 /* reset tst_count in case we are looping */ 91 tst_count = 0; 92 93 //block1: 94 tst_resm(TINFO, "Enter Block 1: test with bad fd"); 95 if (write(-1, pbuf, 1) != -1) { 96 tst_resm(TFAIL, "write of invalid fd passed"); 97 } else { 98 if (errno != EBADF) { 99 tst_resm(TFAIL, "expected EBADF got %d", errno); 100 } 101 tst_resm(TPASS, "received EBADF as expected."); 102 } 103 tst_resm(TINFO, "Exit Block 1"); 104 105 //block2: 106 tst_resm(TINFO, "Enter Block 2: test with a bad address"); 107 fd = creat(filename, 0644); 108 if (fd < 0) { 109 tst_resm(TFAIL, "creating a new file failed"); 110 cleanup(); 111 } 112 if (write(fd, bad_addr, 10) != -1) { 113 tst_resm(TFAIL, "write() on an invalid buffer " 114 "succeeded, but should have failed"); 115 cleanup(); 116 } else { 117 if (errno != EFAULT) { 118 tst_resm(TFAIL, "write() returned illegal " 119 "errno: expected EFAULT, got %d", 120 errno); 121 cleanup(); 122 } 123 tst_resm(TPASS, "received EFAULT as expected."); 124 } 125 tst_resm(TINFO, "Exit Block 2"); 126 127 //block3: 128 tst_resm(TINFO, "Enter Block 3: test with invalid pipe"); 129 if ((pid = FORK_OR_VFORK()) == 0) { /* child */ 130 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 131 tst_resm(TINFO, "signal failed"); 132 } 133 if (pipe(pipefildes) == -1) { 134 tst_brkm(TBROK, NULL, "can't open pipe"); 135 exit(errno); 136 } 137 close(pipefildes[0]); 138 if (write(pipefildes[1], pbuf, 1) != -1) { 139 tst_resm(TFAIL, "write on read-closed" 140 "pipe succeeded"); 141 exit(-1); 142 } else { 143 if (errno != EPIPE) { 144 tst_resm(TFAIL, "write() failed to set" 145 " errno to EPIPE, got: %d", 146 errno); 147 exit(errno); 148 } 149 exit(0); 150 } 151 } else { 152 if (pid < 0) { 153 tst_resm(TFAIL, "Fork failed"); 154 } 155 wait(&status); 156 if (WIFSIGNALED(status) && 157 WTERMSIG(status) == SIGPIPE) { 158 tst_resm(TFAIL, "child set SIGPIPE in exit"); 159 } else if (WEXITSTATUS(status) != 0) { 160 tst_resm(TFAIL, "exit status from child " 161 "expected 0 got %d", status >> 8); 162 } else { 163 tst_resm(TPASS, "received EPIPE as expected."); 164 } 165 tst_resm(TINFO, "Exit Block 3"); 166 } 167 close(fd); 168 } 169 cleanup(); 170 tst_exit(); 171 } 172 173 /* 174 * setup() 175 * performs all ONE TIME setup for this test 176 */ 177 void setup(void) 178 { 179 180 tst_sig(FORK, DEF_HANDLER, cleanup); 181 182 /* Pause if that option was specified 183 * TEST_PAUSE contains the code to fork the test with the -i option. 184 * You want to make sure you do this before you create your temporary 185 * directory. 186 */ 187 TEST_PAUSE; 188 189 /* Create a unique temporary directory and chdir() to it. */ 190 tst_tmpdir(); 191 192 sprintf(filename, "write05.%d", getpid()); 193 194 bad_addr = mmap(0, 1, PROT_NONE, 195 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 196 if (bad_addr == MAP_FAILED) { 197 printf("mmap failed\n"); 198 } 199 200 } 201 202 /* 203 * cleanup() 204 * performs all ONE TIME cleanup for this test at 205 * completion or premature exit 206 */ 207 void cleanup(void) 208 { 209 210 /* Close the file descriptor befor removing the file */ 211 close(fd); 212 213 unlink(filename); 214 tst_rmdir(); 215 216 } 217