Home | History | Annotate | Download | only in write
      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  *	write04.c
     23  *
     24  * DESCRIPTION
     25  *	Testcase to check that write() sets errno to EAGAIN
     26  *
     27  * ALGORITHM
     28  *	Create a named pipe (fifo), open it in O_NONBLOCK mode, and
     29  *	attempt to write to it when it is full, write(2) should fail
     30  *	with EAGAIN.
     31  *
     32  * USAGE:  <for command-line>
     33  *      write04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     34  *      where,  -c n : Run n copies concurrently.
     35  *              -e   : Turn on errno logging.
     36  *              -i n : Execute test n times.
     37  *              -I x : Execute test for x seconds.
     38  *              -P x : Pause for x seconds between iterations.
     39  *              -t   : Turn on syscall timing.
     40  *
     41  * HISTORY
     42  *      ??/???? someone made this testcase but didn't add HISTORY
     43  *
     44  * RESTRICTIONS
     45  *	NONE
     46  */
     47 
     48 #include <sys/stat.h>
     49 #include <fcntl.h>
     50 #include <signal.h>
     51 #include <setjmp.h>
     52 #include <errno.h>
     53 #include <string.h>
     54 #include "test.h"
     55 
     56 #define PIPE_SIZE_TEST getpagesize()
     57 
     58 void alarm_handler();
     59 void setup();
     60 void cleanup();
     61 
     62 char *TCID = "write04";
     63 int TST_TOTAL = 1;
     64 
     65 char fifo[100] = "fifo";
     66 static sigjmp_buf jmp;
     67 int rfd, wfd;
     68 
     69 int main(int argc, char **argv)
     70 {
     71 	int lc;
     72 
     73 	struct stat buf;
     74 	int fail;
     75 	int cnt;
     76 	char wbuf[17 * PIPE_SIZE_TEST];
     77 	struct sigaction sigptr;	/* set up signal handler */
     78 
     79 	tst_parse_opts(argc, argv, NULL, NULL);
     80 
     81 	/* global setup */
     82 	setup();
     83 
     84 	/*
     85 	 * The following loop checks looping state if -i option given
     86 	 */
     87 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     88 		/* reset tst_count in case we are looping */
     89 		tst_count = 0;
     90 
     91 		if (mknod(fifo, S_IFIFO | 0777, 0) < 0) {
     92 			tst_resm(TBROK, "mknod() failed, errno: %d", errno);
     93 			cleanup();
     94 		}
     95 		if (stat(fifo, &buf) != 0) {
     96 			tst_resm(TBROK, "stat() failed, errno: %d", errno);
     97 			cleanup();
     98 		}
     99 		if ((buf.st_mode & S_IFIFO) == 0) {
    100 			tst_resm(TBROK, "Mode does not indicate fifo file");
    101 			cleanup();
    102 		}
    103 #if 0
    104 		sigset(SIGALRM, alarm_handler);
    105 #endif
    106 		sigptr.sa_handler = (void (*)(int signal))alarm_handler;
    107 		sigfillset(&sigptr.sa_mask);
    108 		sigptr.sa_flags = 0;
    109 		sigaddset(&sigptr.sa_mask, SIGALRM);
    110 		if (sigaction(SIGALRM, &sigptr, NULL) == -1) {
    111 			tst_resm(TBROK, "sigaction(): Failed");
    112 			cleanup();
    113 		}
    114 //block1:
    115 		tst_resm(TINFO, "Enter block 1: test for EAGAIN in write()");
    116 		fail = 0;
    117 
    118 		(void)memset((void *)wbuf, 'A', 17 * PIPE_SIZE_TEST);
    119 
    120 		/*
    121 		 * open the read end of the pipe
    122 		 */
    123 		if (sigsetjmp(jmp, 1)) {
    124 			tst_resm(TBROK, "Error reading fifo, read blocked");
    125 			fail = 1;
    126 		}
    127 		(void)alarm(10);	/* set alarm for 10 seconds */
    128 		rfd = open(fifo, O_RDONLY | O_NONBLOCK);
    129 		(void)alarm(0);
    130 		if (rfd < 0) {
    131 			tst_resm(TBROK, "open() for reading the pipe failed");
    132 			fail = 1;
    133 		}
    134 
    135 		/*
    136 		 * open the write end of the pipe
    137 		 */
    138 		if (sigsetjmp(jmp, 1)) {
    139 			tst_resm(TBROK, "setjmp() failed");
    140 			cleanup();
    141 		}
    142 		(void)alarm(10);	/* set alarm for 10 seconds */
    143 		wfd = open(fifo, O_WRONLY | O_NONBLOCK);
    144 		(void)alarm(0);
    145 		if (wfd < 0) {
    146 			tst_resm(TBROK, "open() for writing the pipe failed");
    147 			fail = 1;
    148 		}
    149 
    150 		/*
    151 		 * attempt to fill the pipe with some data
    152 		 */
    153 		if (sigsetjmp(jmp, 1)) {
    154 			tst_resm(TBROK, "sigsetjmp() failed");
    155 			fail = 1;
    156 		}
    157 		(void)alarm(10);
    158 		cnt = write(wfd, wbuf, 17 * PIPE_SIZE_TEST);
    159 		(void)alarm(0);
    160 		if (cnt == 17 * PIPE_SIZE_TEST) {
    161 			tst_resm(TBROK, "Error reading fifo, nozero read");
    162 			fail = 1;
    163 		}
    164 
    165 		/*
    166 		 * Now that the fifo is full try and send some more
    167 		 */
    168 		if (sigsetjmp(jmp, 1)) {
    169 			tst_resm(TBROK, "sigsetjmp() failed");
    170 			fail = 1;
    171 		}
    172 		(void)alarm(10);
    173 		cnt = write(wfd, wbuf, 8 * PIPE_SIZE_TEST);
    174 		(void)alarm(0);
    175 		if (cnt != -1) {
    176 			tst_resm(TBROK, "write() failed to fail when pipe "
    177 				 "is full");
    178 			fail = 1;
    179 		} else {
    180 			if (errno != EAGAIN) {
    181 				tst_resm(TBROK, "write set bad errno, expected "
    182 					 "EAGAIN, got %d", errno);
    183 				fail = 1;
    184 			}
    185 			tst_resm(TINFO, "read() succeded in setting errno to "
    186 				 "EAGAIN");
    187 		}
    188 		if (fail) {
    189 			tst_resm(TFAIL, "Block 1 FAILED");
    190 		} else {
    191 			tst_resm(TPASS, "Block 1 PASSED");
    192 		}
    193 		tst_resm(TINFO, "Exit block 1");
    194 
    195 		/* unlink fifo in case we are looping. */
    196 		unlink(fifo);
    197 	}
    198 	cleanup();
    199 	tst_exit();
    200 }
    201 
    202 void alarm_handler(void)
    203 {
    204 	siglongjmp(jmp, 1);
    205 }
    206 
    207 /*
    208  * setup()
    209  *	performs all ONE TIME setup for this test
    210  */
    211 void setup(void)
    212 {
    213 
    214 	tst_sig(FORK, DEF_HANDLER, cleanup);
    215 
    216 	/* Pause if that option was specified
    217 	 * TEST_PAUSE contains the code to fork the test with the -i option.
    218 	 * You want to make sure you do this before you create your temporary
    219 	 * directory.
    220 	 */
    221 	TEST_PAUSE;
    222 
    223 	/* Create a unique temporary directory and chdir() to it. */
    224 	tst_tmpdir();
    225 
    226 	/* create a temporary filename */
    227 	sprintf(fifo, "%s.%d", fifo, getpid());
    228 
    229 }
    230 
    231 void cleanup(void)
    232 {
    233 
    234 	close(rfd);
    235 	close(wfd);
    236 	unlink(fifo);
    237 	tst_rmdir();
    238 
    239 }
    240