write04.c revision cff4af016805c764c391c473d4c95b999dcdf148
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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#include "usctest.h"
56
57#define PIPE_SIZE_TEST getpagesize()
58
59void alarm_handler();
60void setup();
61void cleanup();
62
63char *TCID = "write04";
64int TST_TOTAL = 1;
65extern int Tst_count;
66
67/* 0 terminated list of expected errnos */
68int exp_enos[] = {11,0};
69
70char fifo[100] = "fifo";
71static sigjmp_buf jmp;
72int rfd, wfd;
73
74int main(int argc, char **argv)
75{
76	int lc;
77	char *msg;
78
79	struct stat buf;
80	int fail;
81	int cnt;
82	char wbuf[17 * PIPE_SIZE_TEST];
83	struct sigaction sigptr; /* set up signal handler */
84
85	/* parse standard options */
86	if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
87			(char *) NULL) {
88		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
89		/*NOTREACHED*/
90	}
91
92	/* global setup */
93	setup();
94
95	/*
96	 * The following loop checks looping state if -i option given
97	 */
98	for (lc = 0; TEST_LOOPING(lc); lc++) {
99		/* reset Tst_count in case we are looping */
100		Tst_count = 0;
101
102		if (mknod(fifo, S_IFIFO | 0777, 0) < 0) {
103			tst_resm(TBROK, "mknod() failed, errno: %d", errno);
104			cleanup();
105			/*NOTREACHED*/
106		}
107		if (stat(fifo, &buf) != 0) {
108			tst_resm(TBROK, "stat() failed, errno: %d", errno);
109			cleanup();
110			/*NOTREACHED*/
111		}
112		if ((buf.st_mode & S_IFIFO) == 0) {
113			tst_resm(TBROK, "Mode does not indicate fifo file");
114			cleanup();
115			/*NOTREACHED*/
116		}
117#if 0
118		sigset(SIGALRM, alarm_handler);
119#endif
120		sigptr.sa_handler = (void (*)(int signal))alarm_handler;
121		sigfillset(&sigptr.sa_mask);
122		sigptr.sa_flags = 0;
123		sigaddset(&sigptr.sa_mask, SIGALRM);
124		if (sigaction(SIGALRM, &sigptr, (struct sigaction *)NULL) == -1)
125		{
126			tst_resm(TBROK, "sigaction(): Failed");
127			cleanup();
128		}
129
130
131//block1:
132		tst_resm(TINFO, "Enter block 1: test for EAGAIN in write()");
133		fail = 0;
134
135		(void)memset((void *)wbuf, 'A', 17*PIPE_SIZE_TEST);
136
137		/*
138		 * open the read end of the pipe
139		 */
140		if (sigsetjmp(jmp, 1)) {
141			tst_resm(TBROK, "Error reading fifo, read blocked");
142			fail = 1;
143		}
144		(void)alarm(10);		/* set alarm for 10 seconds */
145		rfd = open(fifo, O_RDONLY | O_NONBLOCK);
146		(void)alarm(0);
147		if (rfd < 0) {
148			tst_resm(TBROK, "open() for reading the pipe failed");
149			fail = 1;
150		}
151
152		/*
153		 * open the write end of the pipe
154		 */
155		if (sigsetjmp(jmp, 1)) {
156			tst_resm(TBROK, "setjmp() failed");
157			cleanup();
158			/*NOTREACHED*/
159		}
160		(void)alarm(10);		/* set alarm for 10 seconds */
161		wfd = open(fifo, O_WRONLY | O_NONBLOCK);
162		(void)alarm(0);
163		if (wfd < 0) {
164			tst_resm(TBROK, "open() for writing the pipe failed");
165			fail = 1;
166		}
167
168		/*
169		 * attempt to fill the pipe with some data
170		 */
171		if (sigsetjmp(jmp, 1)) {
172			tst_resm(TBROK, "sigsetjmp() failed");
173			fail = 1;
174		}
175		(void)alarm(10);
176		cnt = write(wfd, wbuf, 17*PIPE_SIZE_TEST);
177		(void)alarm(0);
178		if (cnt == 17 * PIPE_SIZE_TEST) {
179			tst_resm(TBROK, "Error reading fifo, nozero read");
180			fail = 1;
181		}
182
183		/*
184		 * Now that the fifo is full try and send some more
185		 */
186		if (sigsetjmp(jmp, 1)) {
187			tst_resm(TBROK, "sigsetjmp() failed");
188			fail = 1;
189		}
190		(void)alarm(10);
191		cnt = write(wfd, wbuf, 8*PIPE_SIZE_TEST);
192		(void)alarm(0);
193		if (cnt != -1) {
194			tst_resm(TBROK, "write() failed to fail when pipe "
195				 "is full");
196			fail = 1;
197		} else {
198			TEST_ERROR_LOG(errno);
199			if (errno != EAGAIN) {
200				tst_resm(TBROK, "write set bad errno, expected "
201					 "EAGAIN, got %d", errno);
202				fail = 1;
203			}
204			tst_resm(TINFO, "read() succeded in setting errno to "
205				 "EAGAIN");
206		}
207		if (fail) {
208			tst_resm(TFAIL, "Block 1 FAILED");
209		} else {
210			tst_resm(TPASS, "Block 1 PASSED");
211		}
212		tst_resm(TINFO, "Exit block 1");
213
214		/* unlink fifo in case we are looping. */
215		unlink(fifo);
216	}
217	cleanup();
218	/*NOTREACHED*/
219	return(0);
220}
221
222void
223alarm_handler()
224{
225	siglongjmp(jmp, 1);
226}
227
228/*
229 * setup()
230 *	performs all ONE TIME setup for this test
231 */
232void
233setup(void)
234{
235	/* capture signals */
236	tst_sig(FORK, DEF_HANDLER, cleanup);
237
238	/* Set up the expected error numbers for -e option */
239	TEST_EXP_ENOS(exp_enos);
240
241	/* Pause if that option was specified
242	 * TEST_PAUSE contains the code to fork the test with the -i option.
243	 * You want to make sure you do this before you create your temporary
244	 * directory.
245	 */
246	TEST_PAUSE;
247
248	/* Create a unique temporary directory and chdir() to it. */
249	tst_tmpdir();
250
251	/* create a temporary filename */
252	sprintf(fifo, "%s.%d", fifo, getpid());
253
254}
255
256void
257cleanup()
258{
259	/*
260	 * print errno log if that option was specified.
261	 */
262	TEST_CLEANUP;
263
264	close(rfd);
265	close(wfd);
266	unlink(fifo);
267	tst_rmdir();
268
269	/* exit with return code appropriate for results */
270	tst_exit();
271	/*NOTREACHED*/
272}
273